+
    Pj
9                       ^ RI t ^ RIt^ RIt^ RIt^ RIt^ RIHt ^ RIHt ^ RI	H
t
Ht ^ RIHt ^ RIHt ^ RI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HtHtHt ^R
I H!t! ^RI"H#t#H$t$H%t% ^RI&H't'H(t( ^RI)H*t*H+t+ ^RI,H-t- ]+P\                  ! ]/4      t0Rt1Rt2Rt3Rt4Rt5Rt6Rt7Rt8RGt9Rt:^2t;Rt<RHt=^t>Rt?Rt@R R ltAR R ltB]
 ! R R 4      4       tC]
 ! R! R"4      4       tD]
 ! R# R$4      4       tE ! R% R&4      tFR' R( ltGR) R* ltHR+ R, ltI ! R- R.4      tJ ! R/ R04      tK ! R1 R24      tL ! R3 R44      tMR5 R6 ltNR7 R8 ltOR9 R: ltPR;R/R< R= lltQR;R/R> R? lltRR@ RA ltSRB RC ltTR;RRD^/RE RF lltUR# )I    N)ThreadPoolExecutor)contextmanager)	dataclassfield)Path)	token_hex)AnyBinaryIOCallableIteratorListLiteraloverload)	constants)
CachedHostdelete_pool_cacheread_pool_cachesave_pool_cache)Volume)HfHubHTTPErrorSandboxCommandErrorSandboxError)HfApiJobInfo)	get_tokenlogging)parse_durationi?  z
hf-sandboxzhf-sandbox-mode	dedicatedpoolzhf-sandbox-poolzhf-sandbox-noncezpython:3.1224h.z/.hf-sbx-servera  set -e
d=/tmp/.sbx-server
if command -v wget >/dev/null 2>&1; then wget -q --header "Authorization: Bearer $SBX_DL_TOKEN" -O "$d" "$SBX_SERVER_URL"
elif command -v curl >/dev/null 2>&1; then curl -fsSL -H "Authorization: Bearer $SBX_DL_TOKEN" -o "$d" "$SBX_SERVER_URL"
else cp "$SBX_SERVER_MOUNT/sbx-server" "$d"; fi
chmod +x "$d"
unset SBX_DL_TOKEN SBX_SERVER_URL SBX_SERVER_MOUNT
exec "$d"
c                <    V ^8  d   QhR\         R\         R\         /# )   hf_tokennoncereturnstr)formats   "q/Users/ahmed/devFolder/Ultron/claude-voice/gateway/.venv/lib/python3.14/site-packages/huggingface_hub/_sandbox.py__annotate__r+   ]   s&     c cC c c c    c                    \         P                  ! V P                  4       RV 2P                  4       \        P                  4      P                  4       # )a%  Derive the per-sandbox auth token from the user's HF token and the sandbox nonce.

Stateless: any machine holding the same HF token can recompute it from the
nonce stored in the job's labels, so `Sandbox.connect(job_id)` needs no local state.
The HF token itself is never sent to the sandbox.
zhf-sandbox:)hmacnewencodehashlibsha256	hexdigest)r$   r%   s   &&r*   _derive_sandbox_tokenr4   ]   s;     88HOO%UG'<'C'C'Ew~~V``bbr,   c                \    V ^8  d   QhR\         \        ,          \        ,          R\         /# )r#   durationr&   )intfloatr(   )r)   s   "r*   r+   r+   g   s#     $ $ec 1 $c $r,   c                f    \        V \        \        34      '       d   \        V 4      # \        V 4      # )zBParse a duration like 300, "300s", "10m", "2h", "1d" into seconds.)
isinstancer7   r8   r   )r6   s   &r*   _duration_to_secsr;   g   s(    (S%L))8}(##r,   c                   j   a  ] tR t^nt o RtRtRt^ t]V 3R lR l4       t	V 3R lR lt
V 3R ltR	tV tR# )
SandboxCommandResultz?Result of a command executed in a sandbox with [`Sandbox.run`].NFc                    < V ^8  d   QhRS[ /# r#   r&   bool)r)   __classdict__s   "r*   r+   !SandboxCommandResult.__annotate__z   s     # #D #r,   c                     V P                   ^ 8H  # r   )	exit_codeselfs   &r*   okSandboxCommandResult.oky   s    ~~""r,   c                    < V ^8  d   QhRS[ /# r?   r'   )r)   rB   s   "r*   r+   rC   }   s     s s# sr,   c                    \        V P                  4      ^P8:  d   V P                  MV P                  R,          R,           pRV P                   RV: RV P                   R2# )P   :NM   Nz...zSandboxCommandResult(exit_code=z	, stdout=z, duration_ms=))lenstdoutrF   duration_ms)rH   outs   & r*   __repr__SandboxCommandResult.__repr__}   sU     -3dkkS9IE9Q00@	#P^_c_o_o^ppqrrr,   c                ~   < V ^8  d   Qh/ S[ R,          ;R&   S[;R&   S[;R&   S[ R,          ;R&   S[;R&   S[ ;R&   # )r#   NrF   rQ   stderrsignal	timed_outrR   )r7   r(   rA   )r)   rB   s   "r*   r+   rC   n   sY      Tz	 
 K  K  $J     r,    )__name__
__module____qualname____firstlineno____doc__rX   rY   rR   propertyrI   rT   __annotate_func____static_attributes____classdictcell__rB   s   @r*   r=   r=   n   s>     I
 FIK# #s s  r,   r=   c                   f   a  ] tR t^t o Rt]! RRR7      tRtRtRt	Rt
V 3R lR ltV 3R ltR	tV tR# )
SandboxProcessaq  A background process started in a sandbox with [`Sandbox.run`]`(..., background=True)`.

List a sandbox's processes with [`Sandbox.processes`] and stop one with [`SandboxProcess.kill`].
Completed processes stay in the listing until the sandbox is deleted, so `running` and
`exit_code` tell whether a process is still alive or already exited (as of when it was listed).
F)reprcompareNTc                   < V ^8  d   QhRR/# r#   r&   NrZ   )r)   rB   s   "r*   r+   SandboxProcess.__annotate__   s     C Cd Cr,   c                X    V P                   P                  RRV P                   24       R# )z:Terminate the background process (idempotent server-side).DELETEz/processes/N)_sandbox_requestpidrG   s   &r*   killSandboxProcess.kill   s!    x;txxj)ABr,   c                   < V ^8  d   Qh/ S[ ;R&   S[S[S[,          ,          ;R&   R;R&   S[R,          ;R&   S[ R,          ;R&   S[;R&   S[ R,          ;R	&   # )
r#   rp   cmdSandboxrn   Ntagstarted_at_msrunningrF   )r7   r(   r   rA   )r)   rB   s   "r*   r+   rk      ss      
H  
tCy  :  
t  :$   ! " Tz # r,   rZ   )r[   r\   r]   r^   r_   r   rn   rv   rw   rx   rF   rq   ra   rb   rc   rd   s   @r*   rf   rf      s?       UE:HC $MG IC C'  r,   rf   c                   8   a  ] tR t^t o RtRtRtV 3R ltRtV t	R# )	FileEntryz%A file or directory inside a sandbox.N c                ~   < V ^8  d   Qh/ S[ ;R&   S[ ;R&   S[R,          ;R&   S[;R&   S[R,          ;R&   S[ ;R&   # )	r#   namepathtypesizeNmtime_msmode)filedirsymlink)r(   r   r7   )r)   rB   s   "r*   r+   FileEntry.__annotate__   sY      I	 
 I  *
++  I  Dj  N r,   rZ   )
r[   r\   r]   r^   r_   r   r   ra   rb   rc   rd   s   @r*   rz   rz      s     /  HD  r,   rz   c                   N  a  ] tR t^t o RtR"tR#t^tV 3R lR ltV 3R lR lt	R$V 3R lR llt
R%V 3R	 lR
 ll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tV 3R lR ltV 3R lR ltV 3R lR ltV 3R lR ltV 3R lR ltR&V 3R lR lltV 3R lR  ltR!tV tR# )'SandboxFilesu-  Filesystem operations inside a sandbox, available as [`Sandbox.files`].

In shared (pool) mode, paths are rooted at the sandbox's private home — the
only place its code can write — so a leading `/` is taken relative to that
home. In dedicated mode, paths are absolute on the container filesystem.
c                "   < V ^8  d   QhRRRR/# )r#   sandboxru   r&   NrZ   )r)   rB   s   "r*   r+   SandboxFiles.__annotate__   s        	  d  r,   c                    Wn         R # Nrn   rH   r   s   &&r*   __init__SandboxFiles.__init__   s    r,   c                &   < V ^8  d   QhRS[ RS[/# r#   r~   r&   r(   bytes)r)   rB   s   "r*   r+   r      s            r,   c                    V P                  V4      P                  pW P                  8  d!   RP                  V P	                  W4      4      # V P
                  P                  RRRV/R7      pVP                  # )z=Read a file from the sandbox and return its content as bytes.r,   GET/files/readr~   params)statr   PARALLEL_THRESHOLDjoin_read_rangesrn   ro   content)rH   r~   r   responses   &&  r*   readSandboxFiles.read   sg    yy##)))88D--d9::==))%PT~)Vr,   c                ,   < V ^8  d   QhRS[ RS[ RS[ /# )r#   r~   encodingr&   r'   )r)   rB   s   "r*   r+   r      s"     0 0c 0S 0s 0r,   c                B    V P                  V4      P                  V4      # )z@Read a file from the sandbox and return its content as a string.)r   decode)rH   r~   r   s   &&&r*   	read_textSandboxFiles.read_text   s    yy%%h//r,   Nc                ^   < V ^8  d   QhRS[ RS[ S[,          S[,          RS[ R,          RR/# r#   r~   datar   Nr&   )r(   r   r
   )r)   rB   s   "r*   r+   r      s=     S S# SS5[8%; S3: SY] Sr,   c                P   \        V\        4      '       d   VP                  4       pM&\        V\        4      '       g   VP	                  4       p\        V4      V P                  8  d   V P                  WV4       R# RV/pVe   W4R&   V P                  P                  RRWBR7       R# )zHWrite content to a file in the sandbox (parent directories are created).Nr~   r   PUT/files/writer   r   )
r:   r(   r0   r   r   rP   r   _write_rangesrn   ro   )rH   r~   r   r   r   s   &&&& r*   writeSandboxFiles.write   s    dC  ;;=DD%((99;Dt9t...t40$!6NunVRr,   c                N   < V ^8  d   QhRS[ S[,          RS[ RS[ R,          RR/# )r#   
local_pathr~   r   Nr&   r(   r   )r)   rB   s   "r*   r+   r      s2     + +t +3 +cDj +TX +r,   c                L   \        V4      P                  4       P                  pW@P                  8  d-   V P	                  V\        V4      P                  4       V4       R# \        VR4      ;_uu_ 4       pV P                  W%VR7       RRR4       R#   + '       g   i     R# ; i)z#Upload a local file to the sandbox.Nrb)r   )r   r   st_sizer   r   
read_bytesopenr   )rH   r   r~   r   r   fs   &&&&  r*   uploadSandboxFiles.upload   sx    J$$&..)))tT*%5%@%@%BDI*d##qJJtTJ* $###s   4BB#	c                :   < V ^8  d   QhRS[ RS[ S[,          RR/# )r#   r~   r   r&   Nr   )r)   rB   s   "r*   r+   r      s&     # #S #cDj #T #r,   c           	     R   V P                  V4      P                  pW0P                  8  dI   \        VR4      ;_uu_ 4       pV P	                  W4       F  pVP                  V4       K  	  RRR4       R# V P                  P                  RRRV/R7      ;_uu_ 4       p\        VR4      ;_uu_ 4       pVP                  RR7       F  pVP                  V4       K  	  RRR4       RRR4       R#   + '       g   i     R# ; i  + '       g   i     L.; i  + '       g   i     R# ; i)	z!Download a file from the sandbox.wbNr   r   r~   r   )
chunk_size   )	r   r   r   r   r   r   rn   _stream
iter_bytes)rH   r~   r   r   r   partr   chunks   &&&     r*   downloadSandboxFiles.download   s    yy##)))j$''1 --d9DGGDM : ( ]]""5-"OOS[j$''1%00K0HEGGEN I ( PO	 (' '' POOs0    *C.D1+D	D.C?	DDD&	c                L   < V ^8  d   QhRS[ RS[S[S[ S[ 3,          ,          /# )r#   r   r&   )r7   r   tuple)r)   rB   s   "r*   r+   r      s,     Y YC YDsCx$9 Yr,   c           	     ~    V P                   p\        ^ W4       Uu. uF  q3\        W!V,
          4      3NK  	  up# u upi rE   )PARALLEL_CHUNK_SIZErangemin)rH   r   r   offsets   &&  r*   _rangesSandboxFiles._ranges   s:    ((BG4BWXBWU6M23BWXXXs   :c                d   < V ^8  d   QhRS[ S[,          RS[S[.S[3,          RS[ S[,          /# )r#   itemsfnr&   )r   r	   r   )r)   rB   s   "r*   r+   r      s5     1 1tCy 1hucz.B 1tCy 1r,   c                    \        V P                  \        V4      4      p\        V4      ;_uu_ 4       p\	        VP                  W!4      4      uuRRR4       #   + '       g   i     R# ; i)zRun `fn(item)` over items concurrently.

All workers share the sandbox's `httpx.Client`, which is thread-safe and pools
connections, so parallel transfers fan out over several streams at once.
N)r   PARALLEL_MAX_WORKERSrP   r   listmap)rH   r   r   workersexecutors   &&&  r*   	_parallelSandboxFiles._parallel   sG     d//U<((HR/0 )(((s   AA)	c                <   < V ^8  d   QhRS[ RS[RS[S[,          /# )r#   r~   r   r&   )r(   r7   r   r   )r)   rB   s   "r*   r+   r      s&     9 9 9C 9DK 9r,   c                \   a a R  VV 3R llpS P                  S P                  V4      V4      # )c                R    V ^8  d   QhR\         \        \        3,          R\        /# )r#   rngr&   )r   r7   r   )r)   s   "r*   r+   /SandboxFiles._read_ranges.<locals>.__annotate__   s"     	$ 	$uS#X 	$5 	$r,   c           
      l   < V w  rSP                   P                  R RRSRVRV/R7      pVP                  # )r   r   r~   r   lengthr   )rn   ro   r   )r   r   r   r   r~   rH   s   &   r*   fetch(SandboxFiles._read_ranges.<locals>.fetch   sF     NF}}--}fdHfhX^-_ . H ###r,   )r   r   )rH   r~   r   r   s   ff& r*   r   SandboxFiles._read_ranges   s)    	$ 	$ ~~dll40%88r,   c                >   < V ^8  d   QhRS[ RS[RS[ R,          RR/# r   r   )r)   rB   s   "r*   r+   r      s-     6 6# 6U 6#* 6 6r,   c                z   a aaa R  VVVV 3R llpS P                  S P                  \        S4      4      V4       R# )c                J    V ^8  d   QhR\         \        \        3,          RR/# )r#   r   r&   N)r   r7   )r)   s   "r*   r+   0SandboxFiles._write_ranges.<locals>.__annotate__  s&     	q 	qeCHo 	q$ 	qr,   c           	      ~   < V w  rR SRV/pSe   SVR&   SP                   P                  RRVSWV,            R7       R# )r~   r   Nr   r   r   r   rn   ro   )r   r   r   r   r   r   r~   rH   s   &   r*   push(SandboxFiles._write_ranges.<locals>.push  sO     NF&,dHf%EF!%vMM""5.QUV\hn_nQo"pr,   N)r   r   rP   )rH   r~   r   r   r   s   ffff r*   r   SandboxFiles._write_ranges   s,    	q 	q 	t||CI.5r,   c                6   < V ^8  d   QhRS[ RS[S[,          /# r   )r(   r   rz   )r)   rB   s   "r*   r+   r   
  s#     L L Li Lr,   c                    V P                   P                  RRRV/R7      pVP                  4       R,           Uu. uF  p\        R/ VB NK  	  up# u upi )z List a directory in the sandbox.r   z/files/listr~   r   entriesrZ   )rn   ro   jsonrz   )rH   r~   r   entrys   &&  r*   r   SandboxFiles.list
  sO    ==))%PT~)V08	0JK0Ju	"E"0JKKKs   Ac                &   < V ^8  d   QhRS[ RS[/# r   )r(   rz   )r)   rB   s   "r*   r+   r     s     , , , ,r,   c                t    V P                   P                  RRRV/R7      p\        R/ VP                  4       B # )z3Get metadata of a file or directory in the sandbox.r   z/files/statr~   r   rZ   )rn   ro   rz   r   )rH   r~   r   s   && r*   r   SandboxFiles.stat  s6    ==))%PT~)V+8==?++r,   c                &   < V ^8  d   QhRS[ RS[/# r   r(   rA   )r)   rB   s   "r*   r+   r     s      3 4 r,   c                     V P                  V4       R#   \         d   pTP                  R8X  d    Rp?R# h Rp?ii ; i)z+Check whether a path exists in the sandbox.Ti  NF)r   r   status_code)rH   r~   es   && r*   existsSandboxFiles.exists  s7    	IIdO 	}}#	s    =88=c                *   < V ^8  d   QhRS[ RS[RR/# )r#   r~   	recursiver&   Nr   )r)   rB   s   "r*   r+   r     s'     I I3 I4 ID Ir,   c                d    RV/pV'       d   RVR&   V P                   P                  RRVR7       R# )z*Delete a file or directory in the sandbox.r~   1r  rm   z/files/deleter   Nr   )rH   r~   r  r   s   &&& r*   deleteSandboxFiles.delete  s1    $"%F;xHr,   c                $   < V ^8  d   QhRS[ RR/# )r#   r~   r&   Nr'   )r)   rB   s   "r*   r+   r   %  s     N N# N$ Nr,   c                F    V P                   P                  RRRV/R7       R# )z0Create a directory (and parents) in the sandbox.POSTz/files/mkdirr~   r   Nr   )rH   r~   s   &&r*   mkdirSandboxFiles.mkdir%  s    v~vtnMr,   r   i    r   )zutf-8r   )F)r[   r\   r]   r^   r_   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r	  rb   rc   rd   s   @r*   r   r      s      ))      0 0S S+ +# #Y Y1 19 96 6L L
, ,
 I IN Nr,   r   c                    V ^8  d   QhR\         \        \         ,          ,          R\        R,          R\        \         \        3,          /# )r#   rt   shellNr&   )r(   r   rA   dictr	   )r)   s   "r*   r+   r+   *  s5     	 	sT#Y 	td{ 	tCH~ 	r,   c                    VRJ d"   \        V \        4      '       g   \        R4      hVRJ d"   \        V \        4      '       d   \        R4      hRV /pVe   WR&   V# )zQBuild the `cmd`/`shell` part of an `/exec` payload, validating their consistency.TzCshell=True requires `cmd` to be a shell command string, not a list.FzRshell=False requires `cmd` to be an argv list (e.g. ['echo', 'hi']), not a string.rt   r  )r:   r(   
ValueError)rt   r  payloads   && r*   _exec_payloadr  *  s\    }ZS11^__~*S#..mnn$clG Nr,   c                Z    V ^8  d   QhR\         P                  R\        \        ,          /# )r#   r   r&   )httpxResponser   r  )r)   s   "r*   r+   r+   6  s"      5>> htn r,   c              #     "   V P                  4        F?  pV'       g   K  \        P                  ! V4      pVP                  R4      R8w  g   K;  Vx  KA  	  R# 5i)zJIterate NDJSON events from a streaming response, skipping keepalive pings.eventpingN)
iter_linesr   loadsget)r   liner  s   &  r*   _iter_eventsr  6  sB     ##%

4 99W'K &s   AA
Ac                <    V ^8  d   QhR\         P                  RR/# )r#   r   r&   N)r  r  )r)   s   "r*   r+   r+   @  s"     s s s4 sr,   c                    V P                  4         V P                  4       R,          p\	        RV P
                   RV 2V P
                  R7      h  \         d    T P                  R,          p LGi ; i)zQRead the error body and raise a SandboxError (works for streaming responses too).error:Ni  NzSandbox API error (z): )r   )r   r   	Exceptiontextr   r   )r   messages   & r*   _raise_for_statusr#  @  sj    MMO&--/'* ,X-A-A,B#gYO]e]q]q
rr  &--%&s   A A10A1c                      a  ] tR tRt o RtR^
R^ /V 3R lR llt]R^
R^ /V 3R lR ll4       t]V 3R	 lR
 l4       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# )_SandboxServeriJ  u5  HTTP transport to one `sbx-server` instance — a dedicated job or a shared host.

Owns the `httpx.Client`, the base URL and the auth headers.
In dedicated mode a server is paired 1:1 with its [`Sandbox`
In pool mode one server (one host job) is shared by many sandboxes, and `live`/`capacity` track packing.
max_connectionscapacityc                b   < V ^8  d   QhRS[ RS[ RS[ R,          RS[ RS[ RS[ RS[R	S[R
S[RR/
# )r#   job_idownerimageNbase_urlr%   sandbox_tokenapir&  r'  r&   )r(   r   r7   )r)   rB   s   "r*   r+   _SandboxServer.__annotate__R  su     &
 &
 &
 	&

 Tz&
 &
 &
 &
 &
 &
 &
 
&
r,   c       	        *   Wn         W n        W0n        W@n        WPn        Wpn        \        V4      V n        W`n        Wn	        ^ V n
        RV n        \        P                  ! RRV P                   2RV/\        P                  ! WR7      RR7      V n        R# )r   TAuthorizationBearer X-Sandbox-Token)r&  max_keepalive_connections)headerslimitsfollow_redirectsN)r)  r*  _imager,  r%   _api_effective_token_auth_token_sandbox_tokenr'  liveverifiedr  ClientLimits_client)
rH   r)  r*  r+  r,  r%   r-  r.  r&  r'  s
   &$$$$$$$$$r*   r   _SandboxServer.__init__R  s     
  
	+C0+ 	  ||74+;+;*<!=!= <<k!
r,   c                B   < V ^8  d   QhRS[ RS[RS[RS[RS[RS[RR/# )	r#   jobr%   r-  r.  r&  r'  r&   r%  )r   r(   r   r7   )r)   rB   s   "r*   r+   r/  {  sS     
 
 
 	

 
 
 
 
 

r,   c                   T ! VP                   VP                  P                  VP                  ;'       g    VP                  \        V4      VVVVVR7	      # )zIBuild a server from a freshly fetched job (reads its exposed server URL).	r)  r*  r+  r,  r%   r-  r.  r&  r'  )idr*  r}   docker_imagespace_id_find_server_url)clsrD  r%   r-  r.  r&  r'  s   &$$$$$$r*   from_job_SandboxServer.from_jobz  sO     66))..""22cll%c*'+

 
	
r,   c                .   < V ^8  d   QhRS[ R,          /# rj   r'   )r)   rB   s   "r*   r+   r/    s      sTz r,   c                    V P                   # r   )r8  rG   s   &r*   r+  _SandboxServer.image  s    {{r,   c                @   < V ^8  d   QhRS[ RS[ RS[P                  /# r#   methodr~   r&   r(   r  r  )r)   rB   s   "r*   r+   r/    s&      c  5>> r,   c                    VP                  R\        P                  ! RRR7      4      pV P                  P                  ! WP
                  V,           3RV/VB pVP                  R8  d   \        V4       V# )z@Request to the in-job server. Raises SandboxError on API errors.timeoutg      N@      $@connect  )popr  TimeoutrA  requestr,  r   r#  rH   rS  r~   kwargsrV  r   s   &&&,  r*   r]  _SandboxServer.request  s`    **YdD(IJ<<''0D`g`Y_`3&h'r,   c                P   < V ^8  d   QhRS[ RS[ RS[S[P                  ,          /# rR  r(   r   r  r  )r)   rB   s   "r*   r+   r/    s+      S  (5>>:R r,   c              +  H  "   VP                  R\        P                  ! RRR7      4      pV P                  P                  ! WP
                  V,           3RV/VB ;_uu_ 4       pVP                  R8  d   \        V4       Vx  RRR4       R#   + '       g   i     R# ; i5i)zJStreaming request to the in-job server. Raises SandboxError on API errors.rV  g     Q@rW  rX  rZ  N)r[  r  r\  rA  streamr,  r   r#  r^  s   &&&,  r*   rd  _SandboxServer.stream  sx      **YdD(IJ\\  )=YwYRXYY]e##s*!(+N ZYYYs   A!B"#!B
B"B		B"c                   < V ^8  d   QhRR/# rj   rZ   )r)   rB   s   "r*   r+   r/    s      t r,   c                :    V P                   P                  4        R # r   )rA  closerG   s   &r*   rh  _SandboxServer.close  s    r,   c                   < V ^8  d   QhRR/# rj   rZ   )r)   rB   s   "r*   r+   r/    s     G GD Gr,   c                h    V P                   P                  V P                  V P                  R 7       R# )r)  	namespaceN)r9  
cancel_jobr)  r*  rG   s   &r*   rn  _SandboxServer.cancel_job  s!    		DKK4::Fr,   c                $   < V ^8  d   QhRS[ RR/# )r#   start_timeoutr&   N)r8   )r)   rB   s   "r*   r+   r/    s     k k k$ kr,   c           
        \         P                   ! 4       V,           pRp\         P                   ! 4       V8  Edl    V P                  P                  V P                  R,           \        P
                  ! R4      R7      pVP                  ^8X  d   R#  \         P                   ! 4       V,
          R8  d   \         P                   ! 4       pV P                  P                  V P                  V P                  R7      pVP                  P                  \        9   dv   \        V P                  V P                  V P                  R7      p\!        R	V P                   R
VP                  P                   RVP                  P"                   RV 24      h\         P$                  ! R4       EK  \!        R	V P                   RVR R24      h  \        P                   d     ELIi ; i)zMPoll /health until the server answers; fail fast (with logs) if the job dies.g        z/healthg      @)rV  Ng       @rl  rm  zSandbox job z$ terminated during startup (status: z, message: ).g333333?z did not become ready within z.0fzs.)timerA  r  r,  r  r\  r   RequestErrorr9  inspect_jobr)  r*  statusstage_TERMINAL_STAGES_tail_job_logsr   r"  sleep)rH   rq  deadlinelast_job_checkr   rD  logss   &&     r*   
wait_ready_SandboxServer.wait_ready  st   99;.iikH$<<++DMMI,Eu}}]`Oa+b''3. / yy{^+c1!%ii++4;;$**+U::##'77)$))T[[DJJWD&&t{{m 4$$'JJ$4$4#5[ASAS@TTVW[V\^  JJt\$++6STabeSffhijj %% s   AG GG)r9  r;  rA  r8  r<  r,  r'  r)  r=  r%   r*  r>  N)r[   r\   r]   r^   r_   r   classmethodrL  r`   r+  r]  r   rd  rh  rn  r  rb   rc   rd   s   @r*   r%  r%  J  s     &
  "&
 &
 &
P 
  "
 
 
 
.      G Gk kr,   r%  c                   n   a  ] tR tRt o Rt]V 3R lR l4       t]V 3R lR l4       tV 3R lR ltR	tV tR
# )_KillMethodi  z>Lets `kill` work both as a classmethod and an instance method.c                8   < V ^8  d   QhRRRS[ RS[R,          /# )r#   instanceNr*  r&   .Nr   r   )r)   rB   s   "r*   r+   _KillMethod.__annotate__  s    NNNTNhy6INr,   c                    R # r   rZ   rH   r  r*  s   &&&r*   __get___KillMethod.__get__  s    KNr,   c                <   < V ^8  d   QhRRRS[ RS[. R3,          /# )r#   r  ru   r*  r&   Nr  )r)   rB   s   "r*   r+   r    s!    RR	R$R8BH;MRr,   c                    R # r   rZ   r  s   &&&r*   r  r    s    ORr,   c                8   < V ^8  d   QhRRRS[ RS[R,          /# )r#   r  Sandbox | Noner*  r&   r  r  )r)   rB   s   "r*   r+   r    s(       0  (9BU r,   c                F   a Ve   VP                   # RR RR /R V3R lllpV# )Nrm  tokenc                \    V ^8  d   QhR\         R\         R,          R\         R,          RR/# )r#   
sandbox_idrm  Nr  r&   r'   )r)   s   "r*   r+   )_KillMethod.__get__.<locals>.__annotate__  s8     	O 	OS 	Od
 	O#PT* 	O`d 	Or,   c                J   < SP                  WVR 7      P                  4        R# ))rm  r  N)rY  rq   )r  rm  r  r*  s   &$$r*   rq   !_KillMethod.__get__.<locals>.kill  s    MM*MGLLNr,   )_kill)rH   r  r*  rq   s   &&f r*   r  r    s7    >>!	OT 	OW[ 	O 	O r,   rZ   N)	r[   r\   r]   r^   r_   r   r  rb   rc   rd   s   @r*   r  r    s.     HN NR R r,   r  c                   l  a  ] tR tRt o RtV 3R lR lt]]3RRR]RR	R
R	RR	RR	RRRRRR	/	V 3R lR lll4       t	]RR	RR	/V 3R lR ll4       t
]! 4       tV 3R lR ltV 3R lR ltV 3R lR ltV 3R lR lt]RRRRR RR!RR"RR#RR$RR%RR&R/	V 3R' lR( ll4       t]RRRRR R/V 3R) lR* ll4       tRR	RR	R R	R!R	R"R	R#R	R$R	R%R+R&R/	V 3R, lR- lltV 3R. lR/ lt]V 3R0 lR1 l4       t]V 3R2 lR3 l4       tRAR4R5/V 3R6 lR7 lllt]V 3R8 lR9 l4       tV 3R: lR; ltV 3R< lR= lt]V 3R> lR? l4       tR@tV tR	# )Bru   i  a  An isolated cloud machine running on Hugging Face Jobs.

Create a dedicated one with [`Sandbox.create`] (one job per sandbox), or get many cheap shared ones from a [`SandboxPool`].
Reattach to a running sandbox from anywhere with [`Sandbox.connect`]. Use as a context manager to terminate it on exit:

```python
>>> from huggingface_hub import Sandbox
>>> with Sandbox.create(image="python:3.12") as sbx:
...     print(sbx.run("python --version").stdout)
```
c                J   < V ^8  d   QhRS[ RS[RS[ R,          RS[RS[RR/# )r#   rG  serverlocal_idNowns_sandboxowns_serverr&   )r(   r%  rA   )r)   rB   s   "r*   r+   Sandbox.__annotate__  sM     ( ( ( 	(
 *( ( ( 
(r,   c                   Wn         W n        W0n        Vf   RMRV 2V n        W@n        WPn        R V n        RV n        \        V 4      V n	        R # )Nz/v1/v1/sandboxes/F)
rG  _server	_local_id
_base_path_owns_sandbox_owns_server_on_kill_killedr   files)rH   rG  r  r  r  r  s   &$$$$$r*   r   Sandbox.__init__  sT     ! $,#3%>(9T * (<@!$'
r,   flavor	cpu-basicidle_timeoutenvNsecretsvolumesrm  forward_hf_tokenFrq        ^@r  c                
  < V ^8  d   QhRS[ RS[ RS[S[,          S[ ,          R,          RS[S[ S[3,          R,          RS[S[ S[3,          R,          RS[S[,          R,          RS[ R,          R	S[R
S[RS[ R,          RR/# )r#   r+  r  r  Nr  r  r  rm  r  rq  r  r&   ru   )r(   r7   r8   r  r	   r   r   rA   )r)   rB   s   "r*   r+   r    s     ba baba 	ba
 EkC'$.ba #s(^d"ba c3h$&ba f$ba :ba ba ba Tzba 
bar,   c       	           \        V
R7      p\        V4      p\        ^4      p\        W4      p\	        VVVVVVVVR7      w  ppppTP                  TTTTT\        \        R\        \        \        V/T;'       g    R\        .VR7
      pRp \        P                  VVVV\        P                  ^,           R7      pVP!                  V	4       T ! TP&                  TRR
R
R7      #   \"         d     TP%                  TP&                  TP(                  P*                  R7       M=  \"         d0   p\,        P/                  RTP&                   R	T 24        Rp?MRp?ii ; iTe   TP1                  4        h i ; i)u;  Create a dedicated sandbox (one HF Job) and block until it is ready (~7s on cpu-basic).

Each sandbox is a full isolated VM, so this is the right choice for GPU
workloads or untrusted code. To fan out many cheap CPU sandboxes instead, use
[`SandboxPool`].

The job runs with a fixed 24h maximum lifetime; `idle_timeout` is the real
keeper — an idle sandbox shuts itself down well before that.

Args:
    image (`str`, *optional*, defaults to `"python:3.12"`):
        Any Docker image with `/bin/sh` (Docker Hub or `hf.co/spaces/...`).
    flavor (`str`, *optional*, defaults to `"cpu-basic"`):
        Hardware flavor, e.g. `"cpu-basic"`, `"a10g-small"`. See `hf jobs hardware`.
    idle_timeout (`int` or `float` or `str`, *optional*, defaults to `600`):
        Auto-shutdown after this much inactivity (no API calls, no running
        processes). Defaults to 10 minutes; pass `None` to disable.
    env (`dict[str, Any]`, *optional*):
        Environment variables available in the sandbox.
    secrets (`dict[str, Any]`, *optional*):
        Secret environment variables (encrypted server-side).
    volumes (`List[Volume]`, *optional*):
        HF repos/buckets to mount, see [`Volume`].
    namespace (`str`, *optional*):
        User or org namespace to run under (defaults to current user).
    forward_hf_token (`bool`, *optional*, defaults to `False`):
        If True, your HF token is injected as `HF_TOKEN` (opt-in).
    start_timeout (`float`, *optional*, defaults to `120.0`):
        Max seconds to wait for the sandbox to become ready.
    token (`str`, *optional*):
        HF token override.

The image only needs `/bin/sh`. The sandbox server is downloaded at startup with
`wget`/`curl` if available, otherwise read off an always-mounted server bucket (which
adds ~2-3s to cold start, so shipping `wget`/`curl` keeps it fast).
r  r  r  r  r  r  r-  r  N
r+  commandr  r  r  rV  labelsr  exposerm  rD  r%   r-  r.  r&  rl  zFailed to cancel sandbox job  after startup failure: TrG  r  r  r  r  )r   r:  r   r4   _bootstrap_job_specrun_jobSANDBOX_MAX_LIFETIMESANDBOX_LABEL
MODE_LABELMODE_DEDICATEDNONCE_LABELSANDBOX_SERVER_PORTr%  rL  r   r   r  r   rn  rG  r*  r}   loggerwarningrh  )rK  r+  r  r  r  r  r  rm  r  rq  r  r.  r$   r%   r-  r  job_envjob_secretsjob_volumesrD  r  r   s   &&$$$$$$$$$           r*   createSandbox.create   s   f % #C("-h>5H%-'	6
2+{ kk(!3
NKQVW''4'(  
 +/	#,,+ , A AA E - F m, cffVd[_``  		dcff		G d!>svvhF^_`^abccd!		s7   A C$ $E501D"!E5"E-%EE5EE5c                L   < V ^8  d   QhRS[ RS[ R,          RS[ R,          RR/# )r#   r  rm  Nr  r&   ru   r'   )r)   rB   s   "r*   r+   r  f  s9     $b $b $bC$J $bcTXj $bdm $br,   c                  \        VR7      p\        W4      w  r\        V9   d   VP                  \        ^4      w  rV\	        WEVR7      p VP                  RR4      P                  4        Uu0 uF  qR,          kK  	  p	pWi9  d   \        RV RV R24      h T ! YTR	R
R7      # VP                  WR7      p
V
P                  ;'       g    / pVP                  \        4      pVP                  \        4      R8w  g   Vf   \        RV R\         R24      hVP                  \        4      \         8X  d   \        RV R\         R24      hV
P"                  P$                  R8w  d'   \        RV RV
P"                  P$                   R24      h\'        \)        V4      V4      p\*        P-                  V
VVV\.        P0                  ^,           R7      pV ! V
P2                  VRR	R
R7      # u upi   \         d    TP                  4        h i ; i)z?Reattach to a running sandbox from anywhere, using only its id.r  rs  r   /v1/sandboxesrG  zSandbox z no longer exists on host r!   FTr  rl  r  NJob z is not a sandbox (missing 'z	' label).z` is a sandbox host, not a single sandbox. Connect to one of its sandboxes with id '<host_job_id>z<local_id>'.RUNNING is not running (status: rt  r  )r   _split_sandbox_idSHARED_ID_SEPsplit_connect_hostr]  r   r   r   rh  rw  r  r  r  r  r  	MODE_POOLrx  ry  r4   r:  r%  rL  r   r   rG  )rK  r  rm  r  r.  host_job_idr  r  itemexistingrD  r  r%   r-  s   &&$$          r*   rY  Sandbox.connecte  s    %  1* H
J&$.$4$4]A$F!K"3yIF39>>%3Y3^3^3`a3`4JJ3`a+&*=WXcWdde'fgg ,
 *hUZhlmmooZoE!!r

;'::m$+u}j\1Mm_\efgg::j!Y.zl #33@/O  ::y(*5NszzO_O_N``bcdd-.>s.CUK(('(==A ) 
 cffVd\`aa9 b  s   "G+ -G&>G+ &G+ +Hc                   < V ^8  d   QhRR/# rj   rZ   )r)   rB   s   "r*   r+   r    s     ! !t !r,   c                   V P                   '       d   R#  V P                  f   V P                  P                  4        M*V P                  P	                  RRV P                   24        RV n         V P                  e   V P                  V 4       V P                  '       d   V P                  P                  4        R# R#   \
         d1   p\        P                  RT P                   RT 24        Rp?R# Rp?ii ; i)zTerminate the sandbox. Idempotent.

Dedicated sandboxes cancel their underlying job; shared sandboxes are
removed from their host (freeing a slot) while the host keeps running.
Nrm   r  zFailed to kill sandbox : T)r  r  r  rn  r]  r   r  r  rG  r  r  rh  )rH   r   s   & r*   r  Sandbox._kill  s     <<<	~~%'')$$X?O/PQ
 ==$MM$LL    	NN4TWWIRsCD	s   (B? )B? ?C:
%C55C:c                   < V ^8  d   QhRR/# rj   rZ   )r)   rB   s   "r*   r+   r    s     ! !t !r,   c                b    V P                   '       d   V P                  P                  4        R# R# )zRelease the local HTTP client without terminating the sandbox. Idempotent.

No-op for pool sandboxes (the client belongs to the pool's host).
N)r  r  rh  rG   s   &r*   rh  Sandbox.close  s%    
 LL  r,   c                   < V ^8  d   QhRR/# )r#   r&   ru   rZ   )r)   rB   s   "r*   r+   r    s      9 r,   c                    V # r   rZ   rG   s   &r*   	__enter__Sandbox.__enter__      r,   c                   < V ^8  d   QhRR/# rj   rZ   )r)   rB   s   "r*   r+   r    s      T r,   c                n    V P                   '       d   V P                  4        R # V P                  4        R # r   )r  rq   rh  rH   exc_infos   &*r*   __exit__Sandbox.__exit__  s     IIKJJLr,   r  .cwdrV  stdin	on_stdout	on_stderrcheck
backgroundc                .  < V ^8  d   QhRS[ S[S[ ,          ,          RS[R,          RS[S[ S[3,          R,          RS[ R,          RS[R,          RS[ R,          RS[S[ .R3,          R,          R	S[S[ .R3,          R,          R
S[RS[R,          RS[/# )r#   rt   r  Nr  r  rV  r  r  r  r  r  Fr&   )	r(   r   rA   r  r	   r8   r   r   r=   )r)   rB   s   "r*   r+   r    s     # #49_# d{	#
 #s(^d"# 4Z# # Tz# SE4K(4/# SE4K(4/# # EN# 
#r,   c       	            R # r   rZ   )rH   rt   r  r  r  rV  r  r  r  r  r  s   &&$$$$$$$$$r*   runSandbox.run  s      #r,   c                   < V ^8  d   QhRS[ S[S[ ,          ,          RS[R,          RS[S[ S[3,          R,          RS[ R,          RS[R,          RS[/# )	r#   rt   r  Nr  r  r  Tr&   )r(   r   rA   r  r	   r   rf   )r)   rB   s   "r*   r+   r    sh      49_ d{	
 #s(^d" 4Z DM 
r,   c                   R # r   rZ   )rH   rt   r  r  r  r  s   &&$$$$r*   r  r    s     r,   Tc                0  < V ^8  d   QhRS[ S[S[ ,          ,          RS[R,          RS[S[ S[3,          R,          RS[ R,          RS[R,          RS[ R,          RS[S[ .R3,          R,          R	S[S[ .R3,          R,          R
S[RS[RS[S[,          /# )r#   rt   r  Nr  r  rV  r  r  r  r  r  r&   )	r(   r   rA   r  r	   r8   r   r=   rf   )r)   rB   s   "r*   r+   r    s     [ [49_[ d{	[
 #s(^d"[ 4Z[ [ Tz[ SE4K(4/[ SE4K(4/[ [ [ 
	.[r,   c       	           \        W4      pV'       d   W;R&   V'       d   WKR&   V
'       dG   V P                  RRVR7      P                  4       p\        VR,          WP	                  R4      V R7      # Ve   W[R
&   Ve   WkR&   . p. pR	pV P                  RRVR7      ;_uu_ 4       p\        V4       F  pVR,          R8X  d0   VP                  VR,          4       Ve   V! VR,          4       K>  K@  VR,          R8X  d0   VP                  VR,          4       Ve   V! VR,          4       K{  K}  VR,          R8X  g   K  \        VR,          RP                  V4      RP                  V4      VP	                  R4      VP	                  RR4      VP	                  R^ 4      R7      pK  	  R	R	R	4       Vf   \        R4      hV	'       d0   VP                  ^ 8w  g   VP                  '       d   \        WR7      hV#   + '       g   i     LX; i)u  Run a command in the sandbox and wait for it, streaming output live.

With `background=True` the command is started detached and `run` returns a
[`SandboxProcess`] immediately, without waiting for it to finish — handy for
servers and other long-running processes. List them later with [`Sandbox.processes`]
and stop one with [`SandboxProcess.kill`]. The streaming/wait-only options
(`timeout`, `stdin`, `on_stdout`, `on_stderr`, `check`) don't apply in that mode.

Args:
    cmd (`str` or `List[str]`):
        A shell command string (run with `/bin/sh -c`) or an argv list (exec'd directly).
    shell (`bool`, *optional*):
        Force the execution mode instead of inferring it from the type of `cmd`.
        `True` runs through `/bin/sh -c` and requires `cmd` to be a string; `False`
        exec's `cmd` directly and requires it to be an argv list. `None` (default)
        infers from the type. Set it explicitly to avoid the type-driven footgun (e.g.
        `["echo hi"]` being exec'd as a single program named `"echo hi"`).
    env (`dict[str, Any]`, *optional*):
        Extra environment variables for this command.
    cwd (`str`, *optional*):
        Working directory.
    timeout (`float`, *optional*):
        Kill the command (whole process group) after this many seconds.
    stdin (`str`, *optional*):
        Data to write to the command's stdin.
    on_stdout (`Callable[[str], None]`, *optional*):
        Callback invoked with stdout chunks as they arrive.
    on_stderr (`Callable[[str], None]`, *optional*):
        Callback invoked with stderr chunks as they arrive.
    check (`bool`, *optional*, defaults to `True`):
        If True, raise [`SandboxCommandError`] on non-zero exit.
    background (`bool`, *optional*, defaults to `False`):
        If True, start the command detached and return a [`SandboxProcess`] right
        away instead of waiting for it and returning a [`SandboxCommandResult`].

Returns: a [`SandboxCommandResult`] (with `exit_code`, `stdout`, `stderr`,
`duration_ms`), or a [`SandboxProcess`] when `background=True`.
r  r  r  
/processesr   rp   rv   )rp   rt   rv   rn   NrV  r  z/execr  rQ   r   rW   exitrF   r{   rX   rY   FrR   )rF   rQ   rW   rX   rY   rR   z%connection lost while running command)rt   result)r  ro   r   rf   r  r   r  appendr=   r   r   rF   rY   r   )rH   rt   r  r  r  rV  r  r  r  r  r  r  r   stdout_partsstderr_partsr   r   r  s   &&$$$$$$$$$       r*   r  r    s   h  + EN EN==G=DIIKD!d5ksZ^__!(I$G"$"$.2\\&'\88H%h/>X- ''f6 ,!%-0 -7^x/ ''f6 ,!%-0 -7^v-1"'"4!ww|4!ww|4$yy2"'))K"?$)IImQ$?F 0 9& >FGGf&&!+v/?/?/?%#==/ 98s   $BG6=A)G66H	c                0   < V ^8  d   QhRS[ S[,          /# r?   )r   rf   )r)   rB   s   "r*   r+   r  2  s     
 
4/ 
r,   c                   V P                  RR4      P                  4       pV Uu. uFW  p\        VR,          VR,          VP                  R4      VP                  R4      VR,          VP                  R4      V R	7      NKY  	  up# u upi )
a  List the background processes of this sandbox.

Returns the processes started with [`Sandbox.run`]`(..., background=True)`; stop one
with [`SandboxProcess.kill`]. Completed processes stay listed (with `running=False` and
their `exit_code`) until the sandbox is deleted.
r   r  rp   rt   rv   rw   rx   rF   )rp   rt   rv   rw   rx   rF   rn   )ro   r   rf   r  )rH   r   ps   &  r*   	processesSandbox.processes2  s     }}UL1668 
  eHeHEE%LeeO4)%%, 
 	
 
s   ABc                .   < V ^8  d   QhRS[ R,          /# rj   r'   )r)   rB   s   "r*   r+   r  J  s     " "sTz "r,   c                .    V P                   P                  # r   )r  r+  rG   s   &r*   r+  Sandbox.imageI  s    ||!!!r,   c                .   < V ^8  d   QhRS[ R,          /# rj   r'   )r)   rB   s   "r*   r+   r  N  s     K Kt Kr,   c                N    V P                   e   V P                  P                  # R# )zIFor a shared/pool sandbox, the job id of the host running it (else None).N)r  r  r)  rG   s   &r*   host_idSandbox.host_idM  s"     '+nn&@t||""JdJr,   schemezhttps://c                B   < V ^8  d   QhRS[ S[,          RS[RS[RS[/# )r#   portr~   r  r&   )r7   r(   )r)   rB   s   "r*   r+   r  T  s4     (N (N#) (N3 (N (N^a (Nr,   c                   V P                   P                  P                  R^4      R,          pVP                  R4      '       d   TMRV,           pV V V P                   RV V 2# )aL  Public URL that proxies through to a server running *inside* this sandbox.

Requests to the returned URL are forwarded by the in-job sandbox server to a
server you started in the sandbox on `port`, including WebSocket (`ws(s)://`)
upgrades and streamed responses. Pair it with [`proxy_headers`] for auth.

How the sandbox must listen on `port`:

- **Pool / shared sandbox**: it cannot bind a TCP port (Landlock), so bind a
  **unix socket** at `$SBX_PROXY_DIR/<port>.sock` (the `SBX_PROXY_DIR` env var
  is set in every sandbox). E.g. `uvicorn app:app --uds $SBX_PROXY_DIR/8000.sock`.
- **Dedicated sandbox**: bind a normal TCP port on `127.0.0.1:<port>`. (You can
  also expose the port directly via the job proxy without going through here.)

Args:
    port (`int` or `str`):
        The port (pool: the `<port>` of the unix socket) the inner server listens on.
    path (`str`, *optional*, defaults to `"/"`):
        Path on the inner server to point at, e.g. `"/ws"`.
    scheme (`str`, *optional*, defaults to `"https://"`):
        URL scheme to build the link with. Defaults to `"https://"`; pass
        `"wss://"` for a WebSocket client (the proxy is protocol-agnostic, so only
        the client-side scheme changes).

Returns:
    `str`: a URL like `https://<job_id>--49983.hf.jobs/v1/.../proxy/8000/ws` (or
    `wss://...` with `scheme="wss://"`).

Example:
    ```python
    >>> url = sandbox.proxy_url_for(8000, "/ws", scheme="wss://")
    >>> import websockets
    >>> async with websockets.connect(url, additional_headers=sandbox.proxy_headers) as ws:
    ...     await ws.send("hello")
    ```
z:///z/proxy/)r  r,  r  
startswithr  )rH   r  r~   r  host_and_rests   &&&$ r*   proxy_url_forSandbox.proxy_url_forT  sa    L --33E1=bAs++tt-(9tfMMr,   c                6   < V ^8  d   QhRS[ S[S[3,          /# r?   )r  r(   )r)   rB   s   "r*   r+   r    s     
 
tCH~ 
r,   c                d    RRV P                   P                   2RV P                   P                  /# )zPAuth headers to send with [`proxy_url_for`] requests (HF token + sandbox token).r1  r2  r3  )r  r;  r<  rG   s   &r*   proxy_headersSandbox.proxy_headers~  s4     wt||'?'?&@At||::
 	
r,   c                    < V ^8  d   QhRS[ /# r?   r'   )r)   rB   s   "r*   r+   r    s     @ @# @r,   c                @    R V P                   : RV P                  : R2# )zSandbox(id=z, image=rO   )rG  r+  rG   s   &r*   rT   Sandbox.__repr__  s    TWWKx

~Q??r,   c                @   < V ^8  d   QhRS[ RS[ RS[P                  /# r#   rS  resourcer&   rT  )r)   rB   s   "r*   r+   r    s+     R Rs Rc R Rr,   c                ^    V P                   P                  ! WP                  V,           3/ VB # r   )r  r]  r  )rH   rS  r#  r_  s   &&&,r*   ro   Sandbox._request  s%    ||##FOOh,FQ&QQr,   c                P   < V ^8  d   QhRS[ RS[ RS[S[P                  ,          /# r"  rb  )r)   rB   s   "r*   r+   r    s+      c S x?W r,   c              +     "   V P                   P                  ! WP                  V,           3/ VB ;_uu_ 4       pVx  R R R 4       R #   + '       g   i     R # ; i5ir   )r  rd  r  )rH   rS  r#  r_  r   s   &&&, r*   r   Sandbox._stream  s?     \\  8)CNvNNRZN ONNNs   7AA
AA		A)	r  r  r  r  r  r  r  r  rG  )r  )r[   r\   r]   r^   r_   r   r  DEFAULT_IMAGEDEFAULT_IDLE_TIMEOUTr  rY  r  rq   r  rh  r  r  r   r  r  r`   r+  r  r  r  rT   ro   r   r   rb   rc   rd   s   @r*   ru   ru     s    
( (:  #ba "	ba
 2Fba &*ba *.ba (,ba !%ba "'ba  %ba !ba ba baH $b $b[_ $b $b $bP =D! !.! !   # !	#
 &)# # !$#  # 36# 36# # &)# # #  !	
 &)   [ "	[
 &*[ [ !%[ ![ 37[ 37[ [ ![ [z
 
. " " K K(Nz (N (NT 
 
@ @
R R  r,   ru   c                   *  a  ] tR tRt o Rt]3RRR]R^RRR	RR
]RRRRRRRR/
V 3R lR lllt]	RRRR/V 3R lR ll4       t
R@V 3R lR lltRRR
]RR/V 3R lR llt]V 3R lR l4       t]V 3R lR l4       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V 3R' lR( ltV 3R) lR* ltV 3R+ lR, ltV 3R- lR. ltV 3R/ lR0 ltV 3R1 lR2 ltV 3R3 lR4 ltV 3R5 lR6 ltV 3R7 lR8 ltV 3R9 lR: ltV 3R; lR< ltV 3R= lR> ltR?t V t!R# )ASandboxPooli  a  A fleet of shared "host" jobs, each packing many landlock-isolated sandboxes.

One host is one billed HF Job (a VM); it runs the sandbox server and multiplexes
up to `sandboxes_per_host` lightweight sandboxes, isolated from each other by
uid + the Landlock LSM. This makes large fan-outs cheap (the VM cost is shared
across all its sandboxes) and fast (creating a sandbox is ~one proxy round-trip
once a host is warm). Best for many parallel CPU sandboxes such as RL rollouts;
for GPU or strong VM-level isolation between mutually-distrusting workloads, use
[`Sandbox.create`] instead.

The constructor pre-provisions `warm_up` hosts (default 1) and blocks until they are
ready; further hosts are then provisioned on demand as sandboxes are requested, and all
are torn down on `close()` (or when idle, via `idle_timeout`). The user never manages jobs:

```python
>>> from huggingface_hub import SandboxPool
>>> with SandboxPool(image="python:3.12", flavor="cpu-basic", warm_up=2) as pool:
...     boxes = [pool.create() for _ in range(100)]   # packed across the warm hosts
...     print(boxes[0].run("echo hi").stdout)
hi
```

`create()` makes **one** sandbox at a time: it reuses a host that still has free
capacity before booting a new one, so you grow on demand as work arrives. To avoid
a cold start on the first few calls, pre-provision hosts with `warm_up` (or
[`warm`]). Warm hosts are discovered via job labels, so reuse works **across
processes** too (a fresh pool with the same `image`/`flavor`/`name` attaches to
hosts an earlier run left behind):

```python
>>> pool = SandboxPool(image="python:3.12")
>>> sbx = pool.create()    # finds a warm host (here or in another process), else boots one
```
r  r  sandboxes_per_hostwarm_up	max_hostsNr}   r  rm  rq  r  r  _connect_modeFc                   < V ^8  d   QhRS[ RS[ RS[RS[RS[R,          RS[ R,          RS[S[,          S[ ,          R,          R	S[ R,          R
S[RS[ R,          RS[RR/# )r#   r+  r  r-  r.  r/  Nr}   r  rm  rq  r  r0  r&   )r(   r7   r8   rA   )r)   rB   s   "r*   r+   SandboxPool.__annotate__  s     `% `%`% 	`%
  `% `% :`% Dj`% EkC'$.`% :`% `% Tz`% `% 
`%r,   c       
        >   V^8  d   \        R4      hV^8  d   \        R4      h\        V
R7      V n        Wn        W n        W0n        W@n        WPn        Ve   TMR\        ^4       2V n	        Wpn
        Wn        Wn        . V n        \        P                  ! 4       V n        \        P                  ! 4       V n        \        P                  ! 4       V n        RV n        RV n        Wn        V'       * V n        \/        4       V n        V'       g   V P3                  4        R# R# )u  Configure a pool and pre-provision `warm_up` hosts (blocks until they are ready).

Env/secrets are *not* set here: they belong to each sandbox and are passed to
`create(env=...)`, so sandboxes in the same pool can have different environments.

Args:
    image (`str`, *optional*, defaults to `"python:3.12"`):
        Docker image for the hosts (needs `/bin/sh`). All sandboxes in the
        pool share this image.
    flavor (`str`, *optional*, defaults to `"cpu-basic"`):
        Hardware flavor for the host jobs (e.g. `"cpu-basic"`).
    sandboxes_per_host (`int`, *optional*, defaults to `50`):
        How many sandboxes to pack per host (per VM density).
    warm_up (`int`, *optional*, defaults to `1`):
        How many hosts to pre-provision in the constructor (which blocks
        until they are ready), so an initial burst of `create()` calls doesn't pay
        a host cold start each. Existing warm hosts (from the cache / other processes)
        count towards it, so only the shortfall is booted; capped by `max_hosts`.
        Defaults to 1 (a single host).
    max_hosts (`int`, *optional*):
        Optional cap on the number of host jobs (a cost ceiling). When
        reached and all hosts are full, `create()` raises.
    name (`str`, *optional*):
        Pool name, used as the `hf-sandbox-pool` job label so the pool is
        discoverable (e.g. `hf sandbox pool ls`, `connect()`). `create()` reuses
        running hosts carrying this label (including from other processes) before
        booting new ones, so distinct names keep separate pools from sharing hosts.
        A random name is generated when omitted.
    idle_timeout (`int` or `float` or `str`, *optional*, defaults to `600`):
        Host idle timeout — a host shuts down once it has had no
        sandboxes for this long (a billing backstop). Each sandbox also has its
        own idle timeout, set at `create()`. Pass `None` to disable.
    namespace (`str`, *optional*):
        User or org namespace to run hosts under.
    start_timeout (`float`, *optional*, defaults to `120.0`):
        Max seconds to wait for a host to become ready.
    token (`str`, *optional*):
        HF token override.
z sandboxes_per_host must be >= 1.zwarm_up must be >= 1.r  Nzpool-F)r  r   r9  r+  r  r-  _warm_upr/  r   r}   _idle_timeout
_namespace_start_timeout_hosts	threadingLock_lock_warmup_lock
_boot_lock_closed
_warmed_up_require_live_host_owns_hostsset_dead_host_ids_ensure_warmed_up)rH   r+  r  r-  r.  r/  r}   r  rm  rq  r  r0  s   &&$$$$$$$$$$r*   r   SandboxPool.__init__  s    l !?@@Q;455&	
"4" ,DE)A,2H	)#+,.^^%
 &NN,
 $..* #0  -,(+
 ""$ r,   c                L   < V ^8  d   QhRS[ RS[ R,          RS[ R,          RR/# )r#   pool_idrm  Nr  r&   r,  r'   )r)   rB   s   "r*   r+   r2    s3     4
 4
c 4
t 4
3QU: 4
an 4
r,   c                  \        V4      pVeT   T ! VP                  VP                  VP                  VP                  TVP
                  Vf   VP                  MTVRR7	      # \        VR7      p\        WQVR7      p\        WVVR7      pVP                  R4      pVP                  R4      p	T ! VP                  ;'       g    VP                  ;'       g    \        VP                  e   \        VP                  4      MR\        VP                  R	\         4      4      V	e   \        V	4      MRTVe   \        V4      MRVVRR7	      # )
u  Reattach to a running pool by id, from any machine — no local state needed.

Finds a running host labelled with `pool_id` and rebuilds the pool's config
(image/flavor/density/host-idle) from that host job's spec and env vars, returning
a [`SandboxPool`] ready to `create()` more sandboxes — packing onto the running
hosts, or booting a duplicate (same config) when they are full.

Raises [`SandboxError`] if no running host is found (a pool stops existing once
all of its hosts are gone — idle-timed-out or killed).

Args:
    pool_id (`str`):
        The id returned when the pool was first created.
    namespace (`str`, *optional*):
        Namespace to search for the pool's hosts (defaults to yours).
    token (`str`, *optional*):
        HF token override.
NT)	r+  r  r-  r/  r}   r  rm  r  r0  r  rs  SBX_IDLE_TIMEOUTSBX_MAX_HOSTSr  SBX_CAPACITY)r   r+  r  r-  r/  r  rm  r   _find_pool_host_job	_host_envr  rH  rI  r)  r(   r7   DEFAULT_SANDBOXES_PER_HOST)
rK  rG  rm  r  cacher.  rD  r  idle_rawmax_hosts_raws
   &&$$      r*   rY  SandboxPool.connect  s   .  (kk||#(#;#;//"//-6->%//I"
 
 % !#)DI677-.0""CCcllCCm&)jj&<3szz?+"377>;U#VW,9,Ec-(4*2*>XD

 
	
r,   c                6   < V ^8  d   QhRS[ RS[S[,          /# )r#   	num_hostsr&   )r7   r   r(   )r)   rB   s   "r*   r+   r2  S  s      c $s) r,   c                `   V P                   '       d   \        R4      hV P                  4        V P                  ;_uu_ 4        V\	        V P
                  4      ,
          pRRR4       X^ 8  dJ   V P                  V4      pV P                  ;_uu_ 4        V P
                  P                  V4       RRR4       V P                  ;_uu_ 4        RV n	        RRR4       V P                  4        V P                  #   + '       g   i     L; i  + '       g   i     Lc; i  + '       g   i     LR; i)uZ  Ensure `num_hosts` empty host(s) are running and leave them running. Returns the
pool's host job ids.

Used to "create" a pool up front: the hosts carry the pool label and config (in
their env vars), so a later `SandboxPool.connect(pool_id)` (even from another
machine) finds them and spawns sandboxes without a cold start. The hosts keep
billing until killed or idle.

Adopts hosts already running for this pool (found via job labels) before booting,
so a `warm()` after `connect()` — or a repeated `warm()` — tops up to `num_hosts`
instead of duplicating live hosts and blowing past `max_hosts`.
This SandboxPool is closed.NT)r>  r   _discover_hostsr;  rP   r8  _provision_hostsextendr<  r?  _save_cachehost_ids)rH   rT  	shortfallbooteds   &&  r*   warmSandboxPool.warmS  s     <<<<==ZZZ!C$44I q=**95F""6* "DO }} Z s$   C7D
D7D	
D	D-	r  r  c                   < V ^8  d   QhRS[ S[S[3,          R,          RS[S[,          S[,          R,          RS[RR/# )r#   r  Nr  r  r&   ru   )r  r(   r	   r7   r8   rA   )r)   rB   s   "r*   r+   r2  n  sV     e e #s(^d"e EkC'$.	e
 e 
er,   c               h   V P                   '       d   \        R4      h\        T;'       g    / 4      pV'       d   \        V P                  4      VR&   Ve   \        V4      MRp. pRp^ p V P                  4         V P                  4       p	V	f+   V'       g#   RpV P                  4        V P                  4       p	V	fl   V P                  '       dI   V'       dA   V P                  '       g/   \        V P                  4       \        RV P                   R24      hV P                  V4      p	V	eA    V P                  WV4      p
T
e   T P'                  4        T
# Y9   d   TP)                  T	4       RpV^,          pV\*        8  g   EK  \        R4      h  \         dU    T P                   ;_uu_ 4        \#        ^ T	P$                  ^,
          4      T	n        RRR4       h   + '       g   i     h ; ii ; i  \         d    T P                   ;_uu_ 4        T P                   Uu. uF  qT9  g   K  TNK  	  Mu upi upT n
        RRR4       M  + '       g   i     M; iT FK  p	 T	P-                  4        M  \         d     Mi ; iT	P/                  4        K8    T	P/                  4        i ; i	  h i ; i)	u  Create one sandbox, provisioning a host if needed.

Reuses a host with free capacity (this pool's, or a warm host found via job labels
/ the local cache) before booting a new one, so a `create()` against a warm host
costs ~one round-trip. Call it repeatedly to fan out; use `warm_up` (or [`warm`])
to pre-provision hosts and avoid a cold start on the first calls. If a host fills
up under us (another process packed it) or a cached host is gone, the sandbox is
re-placed on another host (or a fresh one).

Args:
    env (`dict[str, Any]`, *optional*):
        Environment variables for this sandbox (each sandbox gets its own).
    idle_timeout (`int` or `float` or `str`, *optional*, defaults to `600`):
        Per-sandbox idle timeout — a sandbox is evicted from its host
        after this much inactivity (no API calls, no running process). Distinct
        from the host idle timeout. Pass `None` to disable.
    forward_hf_token (`bool`, *optional*, defaults to `False`):
        If True, inject your HF token as `HF_TOKEN` in the sandbox
        (opt-in). Unlike a dedicated sandbox's `secrets`, a pooled sandbox's env is
        delivered to the host server at creation (never stored in the host job), so
        it doesn't appear in any job's metadata.
rV  HF_TOKENNFT No running host found for pool 'X'. The pool has stopped (all its hosts were killed or idle-timed-out); create a new one.zZCould not place sandbox: hosts kept reporting full. Raise max_hosts or sandboxes_per_host.)r>  r   r  r:  r9  r;   rD  _reserve_onerW  r@  r8  r   r}   _boot_one_host_create_oner   r;  maxr=  rZ  remove_MAX_PACK_ROUNDSrn  rh  )rH   r  r  r  sandbox_env	idle_secs	new_hosts
discoveredroundshostr   hs   &$$$        r*   r  SandboxPool.createn  sR   : <<<<==399"o&6tyy&AK
# 8D7O%l3UY	*,	
<	 ""$((*<
!%J((*,,.D<...:dkkk *$))4*>tyyk J_ _   ..y9D #"&"2"24i"P *((*&
 (!((."
!,,&t % %  "ZZZ(+Atyy1}(=DI ( (Z*  	*.++L+Q)9Kqq+L !!OO%   JJLDJJL " 	s   +,G3 7G3 G3 G3 *AG3 .F  G3 *G3 G3 G00#G	G0G,'	G00G3 3J1I!H5
.H5
4I	J1IJ1$I54J5J JJJJ1J**J1c                    < V ^8  d   QhRS[ /# r?   r7   )r)   rB   s   "r*   r+   r2    s     $ $3 $r,   c                    V P                   ;_uu_ 4        \        V P                  4      uuRRR4       #   + '       g   i     R# ; i)z*Number of host jobs currently provisioned.N)r;  rP   r8  rG   s   &r*   rT  SandboxPool.num_hosts  s%     ZZZt{{# ZZZs	   5A	c                    < V ^8  d   QhRS[ /# r?   rt  )r)   rB   s   "r*   r+   r2    s     : :s :r,   c                    V P                   ;_uu_ 4        \        R V P                   4       4      uuRRR4       #   + '       g   i     R# ; i)z<Number of sandboxes currently handed out (across all hosts).c              3   8   "   T F  qP                   x  K  	  R # 5ir   )r=  ).0rp  s   & r*   	<genexpr>,SandboxPool.num_sandboxes.<locals>.<genexpr>  s     9[Tyy[s   N)r;  sumr8  rG   s   &r*   num_sandboxesSandboxPool.num_sandboxes  s+     ZZZ9T[[99 ZZZs	   <A	c                0   < V ^8  d   QhRS[ S[,          /# r?   )r   r(   )r)   rB   s   "r*   r+   r2    s     9 9$s) 9r,   c                    V P                   ;_uu_ 4        V P                   Uu. uF  qP                  NK  	  upuuRRR4       # u upi   + '       g   i     R# ; i)z!Job ids of the provisioned hosts.N)r;  r8  r)  rH   rp  s   & r*   r[  SandboxPool.host_ids  s9     ZZZ,0KK8KDKKK8 Z8 ZZs   A
AA
A

A	c                   < V ^8  d   QhRR/# rj   rZ   )r)   rB   s   "r*   r+   r2    s     ) )t )r,   c                   V P                   ;_uu_ 4        V P                  p. V n        RV n        RRR4       X F6  p V P                  '       d   VP	                  4        TP                  4        K8  	  V P                  '       d   \        V P                  4       R# R#   + '       g   i     Lw; i  \
         d0   p\        P                  RTP                   RT 24        Rp?LRp?ii ; i  TP                  4        i ; i)u  Release the pool. Idempotent.

For a pool we created, this terminates all host jobs (and therefore all their
sandboxes). For a `connect()`'d handle it only releases the local HTTP clients: the
shared hosts may be serving other clients, so — like [`Sandbox.connect`] — leaving a
`with` block must not tear them down. Terminate a connected pool's hosts explicitly
with `hf sandbox pool delete <id>`.
TNFailed to cancel sandbox host r  )r;  r8  r>  rA  rn  r   r  r  r)  rh  r   r}   )rH   hostsrp  r   s   &   r*   rh  SandboxPool.close  s     ZZZKKEDKDL  D###OO% 

  dii(  Z  T!?}BqcRSST 

s4   B"B2B/	2C,=%C'"C/'C,,C//Dc                   < V ^8  d   QhRR/# )r#   r&   r,  rZ   )r)   rB   s   "r*   r+   r2    s      = r,   c                    V # r   rZ   rG   s   &r*   r  SandboxPool.__enter__  r  r,   c                   < V ^8  d   QhRR/# rj   rZ   )r)   rB   s   "r*   r+   r2    s      T r,   c                &    V P                  4        R # r   )rh  r  s   &*r*   r  SandboxPool.__exit__  s    

r,   c                   < V ^8  d   QhRR/# rj   rZ   )r)   rB   s   "r*   r+   r2    s     ' '4 'r,   c           	        V P                   ;_uu_ 4        V P                  '       d    RRR4       R# V P                  4        V P                  f   V P                  M\        V P                  V P                  4      pV P                  ;_uu_ 4        V\        V P                  4      ,
          pRRR4       X^ 8  d   V P                  4        V P                  '       g   V P                  ;_uu_ 4        V\        V P                  4      ,
          pRRR4       V^ 8  dJ   V P                  V4      pV P                  ;_uu_ 4        V P                  P                  V4       RRR4       RV n        RRR4       V P                  '       d   V P                  4        R# R#   + '       g   i     L; i  + '       g   i     L; i  + '       g   i     Lk; i  + '       g   i     Lo; i)uQ  One-time: seed from the cache and pre-provision up to `warm_up` hosts.

Cheap by default: seeding is local (no HTTP), and if the cache already gives at
least `warm_up` hosts we trust them and skip discovery/booting (dead ones are
pruned lazily by `create()`). Only when short do we list_jobs and boot the
shortfall in parallel, capped by `max_hosts`.

Runs at most once per pool, under `_warmup_lock`: concurrent first `create()` calls
block here until the warm-up completes — and see its hosts — rather than racing past
a half-set flag and each booting their own. `_warmed_up` is only set once the work
succeeds, so a failed warm-up is retried (seeding/discovery dedupe by job id).

Warm-up hosts are pool-level (like [`warm`]): they are not torn down if the
triggering `create()` later fails — `close()` (or the `with` block) reclaims them.
NT)r<  r?  _seed_hosts_from_cacher/  r4  r   r;  rP   r8  rW  r@  rX  rY  rZ  )rH   targetr\  r]  s   &   r*   rD  SandboxPool._ensure_warmed_up  s;       '')&*nn&<T]]#dmmUYUcUcBdF"S%55	 1}$$& ...$*S-=$=	 $ 1}!%!6!6y!A!ZZZ KK..v6 ("DO' , ;;; #  $ (Z# s_   GAGF	.0GG3F0	4GG	 GF-(G0G ;GGGG&	c                   < V ^8  d   QhRR/# )r#   r&   _SandboxServer | NonerZ   )r)   rB   s   "r*   r+   r2  0  s      5 r,   c                    V P                   ;_uu_ 4        V P                   FL  pVP                  VP                  ,
          ^ 8  g   K'  V;P                  ^,          un        Vu uuRRR4       # 	  RRR4       R#   + '       g   i     R# ; i)zNReserve one slot on the first host with free capacity (under lock), else None.N)r;  r8  r'  r=  r  s   & r*   re  SandboxPool._reserve_one0  s\    ZZZ==499,q0IINIK	 Z# 
  Z
 s   /A<	A<0A<<B	c                2   < V ^8  d   QhRS[ R,          RR/# )r#   rm  r%  r&   r  )r   )r)   rB   s   "r*   r+   r2  9  s"     ' '-=(> 'CZ 'r,   c           	        V P                   ;_uu_ 4        V P                  4       pVe   VuuRRR4       # V P                  4       '       d!   V P                  4       pVe   VuuRRR4       # V P                  ^4      pVP	                  V4       V P
                  ;_uu_ 4        V P                  P	                  V4       RRR4       V P                  4       uuRRR4       #   + '       g   i     L*; i  + '       g   i     R# ; i)u0  Provision (or adopt) one host and reserve a slot on it. Returns None to retry.

Held under `_boot_lock` so that, within a process, only one host is booted at a time:
a burst of create() calls that all found every host full queue here, and each new host
frees `sandboxes_per_host` slots for the threads still waiting — so they reuse it instead
of each booting their own. Before booting, we reuse a slot freed by a concurrent boot and,
failing that, adopt a host already SCHEDULING for this pool (here or in another process)
rather than piling on a duplicate.
N)r=  re  _adopt_pending_hostrX  rY  r;  r8  )rH   rm  rp  r]  s   &&  r*   rf  SandboxPool._boot_one_host9  s     ___ $$&D _ ''))((*# _ **1-FV$""6* $$&! _  __s4   C3C3C3,6C3"C 	>C3 C0+C33D	c                    < V ^8  d   QhRS[ /# r?   r@   )r)   rB   s   "r*   r+   r2  U  s     $ $T $r,   c           
       aa V P                    Uu0 uF  qP                  kK  	  upo\        V3R lV P                  P	                  R\
        \        \        V P                  /V P                  R7       4       R4      oSf   R# \        P                  RV P                   RSP                   R24       \        P                  ! 4       V P                  ,           p\        P                  ! 4       V8  d   V P                  P                  SP                  V P                  R	7      P                   P"                  pVR9  d   R# VR
8X  dg   V P%                  4        \&        ;QJ d)    V3R lV P                    4       F  '       g   K   RM	  RM! V3R lV P                    4       4      '       d   R# \        P(                  ! R4       K  R# u upi )a  Wait for and adopt a host already SCHEDULING for this pool, if any.

Avoids over-provisioning when a host is already on its way up for this pool (started by
another process, or an earlier create() in this one): rather than booting a duplicate,
wait for it to reach RUNNING and adopt it via discovery. Returns True if a pending host
was found (whether or not it eventually came up), False if none is scheduling.
c              3   N   <"   T F  pVP                   S9  g   K  Vx  K  	  R # 5ir   )rG  )rz  rD  knowns   & r*   r{  2SandboxPool._adopt_pending_host.<locals>.<genexpr>_  s,      C
 66& s   %
%
SCHEDULINGrx  r  rm  NFzPool 'z' host z: is already SCHEDULING; waiting for it instead of booting.rl  r  c              3   T   <"   T F  qP                   SP                  8H  x  K  	  R # 5ir   r)  rG  )rz  rp  pendings   & r*   r{  r  v  s     I[T{{gjj0[   %(Tg      ?)r  r  )r8  r)  nextr9  	list_jobsr  r  
POOL_LABELr}   r6  r  debugrG  ru  r7  rw  rx  ry  rW  anyr|  )rH   rp  r}  ry  r  r  s   &   @@r*   r  SandboxPool._adopt_pending_hostU  sI    *.5599..'&	:tyyI"oo /  
 ?vdii[

|;uvw99;!4!44iikH$II))t)W^^ddE55	! $$&3IT[[I333IT[[IIIJJsO9 6s   G	c                   < V ^8  d   QhRR/# rj   rZ   )r)   rB   s   "r*   r+   r2  {  s     &/ &/ &/r,   c                  a V P                    Uu0 uF  qP                  kK  	  ppV P                  P                  R\        \
        \        V P                  /V P                  R7       Uu. uF  pVP                  V9  g   K  VNK  	  ppV EFJ  oRp \        V P                  SP                  V P                  R7      p\        V P                  SV P                  R7      p\        VP                  RV P                  4      4      Vn        \!        VP#                  RR4      P%                  4       4      Vn        T P6                  ;_uu_ 4        \8        ;QJ d)    T3R
 lT P                    4       F  '       g   K   RM	  RM! T3R
 lT P                    4       4      '       d   TP5                  4        MT P                   P;                  T4       RRR4       EKM  	  R# u upi u upi   \(        \*        P,                  \.        3 dF   p\0        P3                  RSP                   R	T 24       Te   TP5                  4         Rp?EK  Rp?ii ; i  + '       g   i     EK  ; i)a%  Attach to running host jobs that match this pool (image/flavor/name).

Lets `create()` reuse a host warmed by an earlier call or another process
instead of booting a new one. Hosts are found via job labels; each adopted
host's free capacity is read from the server, so packing stays accurate.
r  r  Nrs  rK  r   r  zSkipping host z during discovery: c              3   T   <"   T F  qP                   SP                  8H  x  K  	  R # 5ir   r  )rz  rp  rD  s   & r*   r{  .SandboxPool._discover_hosts.<locals>.<genexpr>  s     E{{cff,r  TF)r8  r)  r9  r  r  r  r  r}   r6  rG  r  rM  r7   r  r-  r'  rP   r]  r   r=  r   r  	HTTPErrorr   r  r  rh  r;  r  r  )rH   rp  r  rD  matchesr  r  r   s   &  `    r*   rW  SandboxPool._discover_hosts{  s    *.55 yy** "Iz499E// + 

 vvU" C 	 
 CF&tyy#&&DOOT  		3$//J"%cggnd>U>U&V"W!&.."H"M"M"OP 3EE333EEEELLNKK&&v.	 !  6
& !%//>B  ~cffX5HLM%LLN sB   G*G"G"B&G'*I:'I",I' I9III!c                6   < V ^8  d   QhRS[ RS[S[,          /# )r#   num_newr&   )r7   r   r%  )r)   rB   s   "r*   r+   r2    s        ^0D r,   c                t   V P                   ;_uu_ 4        \        V P                  4      pRRR4       V P                  eU   XV,           V P                  8  d=   V P                  V,
          p\	        RV RV P                   R\        ^ V4       R24      h\        \        V^ 4      R7      ;_uu_ 4       p\        V4       Uu. uF  qTP                  V P                  4      NK  	  ppRRR4       . pRpX F#  p	 VP                  V	P                  4       4       K%  	  Ve-   V F$  p VP                  4        VP                  4        K&  	  VhV#   + '       g   i     EL+; iu upi   + '       g   i     L; i  \         d   p
T
p Rp
?
K  Rp
?
ii ; i  \         d     Lli ; i  TP                  4        i ; i)z=Boot `num_new` host jobs in parallel, respecting `max_hosts`.NzPool needs z more host(s) but max_hosts=z allows only z. more. Raise max_hosts or kill some sandboxes.)max_workers)r;  rP   r8  r/  r   rh  r   r   r   submit
_boot_hostr  r   r   rn  rh  )rH   r  currentallowedr   _futuresr]  r  futurer   r  s   &&          r*   rX  SandboxPool._provision_hosts  sq   ZZZ$++&G >>%'G*;dnn*Lnnw.GgY&B4>>BR S"1g//]_   C,<==AFwPAt7GP >')"&Ffmmo. 
  #%%' LLN ! K; ZZ Q >=   !  LLNse   E3E&#E!$E&8E9%FE	!E&&E6	9FFFF"F%!F""F%%F7c                    < V ^8  d   QhRS[ /# r?   r%  )r)   rB   s   "r*   r+   r2    s     > >N >r,   c                >   \        V P                  4      p\        ^4      p\        W4      p\	        V P                  VRRRV P
                  RVR7      w  rErgRVR&   \        V P                  4      VR&   V P                  e   \        V P                  4      VR&   \        R\        \        \        V P                  \        V/pV P                  P                  V P                   TTTV P"                  \$        TT;'       g    R\&        .V P(                  R7
      p	Rp
 \*        P-                  V	VVV P                  \/        V P                  ^,           R	4      V P                  R
7      p
V
P1                  V P2                  4       V
#   \4         d     T P                  P7                  T	P8                  T	P:                  P                  R7       M=  \4         d0   p\<        P?                  RT	P8                   RT 24        Rp?MRp?ii ; iT
e   T
PA                  4        h i ; i)z6Start one host job and wait until its server is ready.NFr  r  SBX_HOST_MODErK  rJ  r     )rD  r%   r-  r.  r&  r'  rl  r  r  )!r:  r9  r   r4   r  r5  r(   r-  r/  r  r  r  r  r}   r  r  r+  r  r  r  r6  r%  rL  r   r  r7  r   rn  rG  r*  r  r  rh  )rH   r$   r%   r-  r  r  r  r  r  rD  r  r   s   &           r*   r  SandboxPool._boot_host  s   #DII."-h>5HII++"'	6
2+ $' 
 #&d&=&="> >>%'*4>>':GO$j)ZT_afgii**;;(''4'(oo   
 +/	 $,,+II #D$;$;a$? E00 - F d112   	e		$$CFFciinn$M e!?xG_`a_bcdde!	s7   A%F H;G	H	H%G>9H>HHc                R   < V ^8  d   QhRRRS[ S[S[3,          RS[R,          RR/# )r#   rp  r%  r  rl  Nr&   r  )r  r(   r	   r7   )r)   rB   s   "r*   r+   r2    s:     $ $ 0 $tCH~ $RUX\R\ $aq $r,   c                   R^/pVe   W4R&   V'       d   W$R&    VP                  RRVR7      P                  4       pR
Tn        TP                  R4      ;'       g    . p\        TP                  R^ 4      4      '       g	   T'       g1   T P                  ;_uu_ 4        TP                  Tn        RRR4       R# T^ ,          p\        TP                   \          TR,           2TTR,          R
RR7      p	T P"                  T	n        T	#   \        \        P                  3 dU   pTP
                  '       d   h \        P                  RTP                   R	T 24       T P                  T4        Rp?R# Rp?ii ; i  + '       g   i     R# ; i)uy  Create one sandbox on a reserved `host`. Returns the sandbox, or None to retry.

None means either the host filled up between our reservation and the create
(server-authoritative capacity — another client packed it, so we mark it full and
place the sandbox elsewhere) or a host rebuilt from the cache is gone/unreachable
(dropped and re-placed via discovery / a fresh boot).
countNidle_timeout_secsr  r  r  r  z!Dropping unreachable cached host r  T	sandboxesrejectedrG  Fr  )r]  r   r   r  r  r>  r  r  r)  
_drop_hostr  r7   r;  r'  r=  ru   r  _on_sandbox_killedr  )
rH   rp  r  rl  bodyr   r   r  r  r   s
   &&&&      r*   rg  SandboxPool._create_one  sJ    !(| (1$%K	<<d<CHHJD HH[)//R	txx
A&''y MM	 |++}od4j\:$Z
  22+ eoo. 	}}}LL<T[[MA3OPOOD!	 s$   "D E7E4 A	E//E47F	c                $   < V ^8  d   QhRS[ RR/# )r#   r   r&   N)ru   )r)   rB   s   "r*   r+   r2  *  s     D D' Dd Dr,   c                    V P                   ;_uu_ 4        \        ^ VP                  P                  ^,
          4      VP                  n        RRR4       R#   + '       g   i     R# ; i)z:Free the packing slot of a shared sandbox that was killed.N)r;  rh  r  r=  r   s   &&r*   r  SandboxPool._on_sandbox_killed*  s9    ZZZ#&q'//*>*>*B#CGOO  ZZZs   7AA'	c                $   < V ^8  d   QhRS[ RR/# )r#   rp  r&   Nr  )r)   rB   s   "r*   r+   r2  /  s      ~ $ r,   c                *   V P                   ;_uu_ 4        V P                   Uu. uF  q"VJg   K
  VNK  	  upV n        V P                  P                  VP                  4       RRR4       VP                  4        R# u upi   + '       g   i     L'; i)zFForget a host found dead this session (and mark it for cache pruning).N)r;  r8  rC  addr)  rh  )rH   rp  rq  s   && r*   r  SandboxPool._drop_host/  sa    ZZZ&*kkCkd]11kCDK##DKK0  	

 D Zs    BA=A=-B=BB	c                   < V ^8  d   QhRR/# rj   rZ   )r)   rB   s   "r*   r+   r2  8  s     + + +r,   c                   \        V P                  4      pVf   R# \        V P                  4      pV P                  ;_uu_ 4        V P
                   Uu0 uF  q3P                  kK  	  ppVP                   F  pVP                  V9   g   VP                  VP                  8  d   K1  \        VP                  VP                  V P                  VP                  VP                  \        W%P                  4      V P                  \!        V P"                  ^,           R4      VP                  R7	      pVP                  Vn        RVn        V P
                  P'                  V4       K  	  RRR4       R# u upi   + '       g   i     R# ; i)u  Adopt the pool's cached hosts without any HTTP (rebuilt from cached URL + nonce).

Best-effort and unverified: each adopted host is confirmed on the first successful
request (and dropped on the first failure, see `_create_one`). Hosts the cache
believes are full are skipped — label discovery re-checks them with fresh counts if
the seeded ones don't satisfy the request, so a stale-full entry never blocks a create.
Nr  rF  F)r   r}   r:  r9  r;  r8  r)  r  r=  r'  r%  r*  r+  r,  r%   r4   r   r-  r>  r  )rH   rO  r$   rp  r  chr  s   &      r*   r  "SandboxPool._seed_hosts_from_cache8  s     		*=#DII.ZZZ-1[[9[T[[[E9kk99%BKK)?'99((**[[(("7(("K		$'(?(?!(CS$I[[
 !gg"'""6*! " Z9 ZZs   E5E0(C>E50E55F	c                   < V ^8  d   QhRR/# rj   rZ   )r)   rB   s   "r*   r+   r2  X  s     
 
T 
r,   c                t   V P                   ;_uu_ 4        V P                   Uu. uFd  p\        VP                  VP                  VP
                  VP                  VP                  VP                  \        P                  ! 4       R7      NKf  	  pp\        V P                  4      pRRR4       \        V P                  V P                  V P                  V P                   V P"                  V P$                  e   \'        V P$                  4      MRV P(                  XXR7	       R# u upi   + '       g   i     L; i)zOPersist the pool config + current hosts (with their live counts) for next time.)r)  r*  r,  r%   r'  r=  
updated_atN)r+  r  r-  r/  r  rm  r  dead_host_ids)r;  r8  r   r)  r*  r,  r%   r'  r=  ru  rB  rC  r   r}   r+  r  r-  r/  r5  r;   r6  )rH   rp  r  deads   &   r*   rZ  SandboxPool._save_cacheX  s    ZZZ !KK (D ;;**!]]**!]]#yy{ (   t**+D  	II**;;#66nnBFBTBTB`*4+=+=>fjoo
	
 Zs   D'A*D"D'"D''D7	)r9  r=  r>  rC  r8  r5  r;  r6  rA  r@  r7  r4  r?  r<  r  r+  r/  r}   r-  )   )"r[   r\   r]   r^   r_   r)  rN  r*  r   r  rY  r^  r  r`   rT  r~  r[  rh  r  r  rD  re  rf  r  rW  rX  r  rg  r  r  r  rZ  rb   rc   rd   s   @r*   r,  r,    s    !J #`% "	`%
 #=`% `% !%`%  `% 2F`% !%`%  %`% !`% $`% `%H 4
d 4
X\ 4
 4
 4
l 6e &*e 2F	e
 "'e eN $ $
 : :
 9 9
) )0  
' 'R ' '8$ $L&/ &/P B> >@$ $LD D
 + +@
 
r,   r,  c                0    V ^8  d   QhR\         R\        /# )r#   r.  r&   )r   r(   )r)   s   "r*   r+   r+   u  s      % C r,   c                     \        V P                  \        4      '       d   V P                  M	\        4       pV'       g   \	        R 4      hV# )zMA Hugging Face token is required to use sandboxes. Run `hf auth login` first.)r:   r  r(   r   r   )r.  r  s   & r*   r:  r:  u  s3    #CIIs33CIIEjkkLr,   c                   V ^8  d   QhR\         R\        R\        \        \        3,          R,          R\        \        \        3,          R,          R\        \
        ,          R,          R\        \        ,          \        ,          R,          R\        R	\        R
\        \        \        ,          \        \        \        3,          \        \        \        3,          \        \
        ,          3,          /	# )r#   r.  r$   r  Nr  r  r  r  r-  r&   )r   r(   r  r	   r   r   r7   r8   rA   r   r   )r)   s   "r*   r+   r+   |  s     $6 $6	$6$6 
c3h$		$6
 #s(^d"$6 &\D $6 +#d*$6 $6 $6 49d38nd38nd6lBC$6r,   c          	        / T;'       g    / CR\        \        4      /Cp/ T;'       g    / CRV/Cp	\        T;'       g    . 4      p
Ve   \        \        V4      4      VR&   V'       d   WR&   V P                   R\
        P                   R2VR&   WR&   \        VR	&   V
P                  \        R
\
        P                  \        RR7      4       RR\        .pWW3# )aE  Build the (command, env, secrets, volumes) to launch a job running sbx-server.

Shared by dedicated sandboxes and shared hosts: both fetch and exec the same unified
`sbx-server` binary at startup (via `/bin/sh`), downloading it with wget/curl, or
reading it off the always-mounted server bucket when the image ships neither.
SBX_PORT	SBX_TOKENrI  rb  z	/buckets/z/resolve/sbx-serverSBX_SERVER_URLSBX_DL_TOKENSBX_SERVER_MOUNTbucketT)r   source
mount_path	read_onlyz/bin/shz-c)r(   r  r   r;   endpointr   SANDBOX_SERVER_BUCKET_SERVER_MOUNT_PATHr  r   _BOOTSTRAP_DOWNLOAD)r.  r$   r  r  r  r  r  r-  r  r  r  r  s   &&$$$$$$    r*   r  r  |  s    & T#))Sj#>Q:RSG"Qgmm"Qk="QKw}}"%K&)*;L*I&J"#"*J#&<<.	):Y:Y9ZZm nG"* #5GHY%D%DQcost $ 34G[55r,   c          
      x    V ^8  d   QhR\         R\        R\        R,          R\        \        \        3,          /# )r#   r.  rD  rm  Nr&   )r   r   r(   r  r	   )r)   s   "r*   r+   r+     s4      5 w cDj T#s(^ r,   c                  \        VP                  \        4      '       d   VP                  M/ pRV9  dL   V P                  VP                  VR7      P                  ;'       g    / p\        V\        4      '       d   TM/ pV# )z6Return a host job's env vars (where pool config lives)rK  rl  )r:   environmentr  rw  rG  )r.  rD  rm  r  s   &&$ r*   rM  rM    sb    '>>#//BCS ooSVVyoAMMSSQST**cJr,   rm  c                V    V ^8  d   QhR\         R\        R\        R,          R\        /# )r#   r.  rG  rm  Nr&   )r   r(   r   )r)   s   "r*   r+   r+     s-     	 	U 	S 	d
 	V] 	r,   c               z    V P                  R\        \        \        V/VR7       F  pVu # 	  \	        RV R24      h)zNReturn any running host job belonging to `pool_id` (found via the pool label).r  r  rc  rd  )r  r  r  r  r   )r.  rG  rm  rD  s   &&$ r*   rL  rL    sT    }}*iW!MYb   
 
*7) 4K 	K r,   c                V    V ^8  d   QhR\         R\        R\        R,          R\        /# )r#   r.  r  rm  Nr&   )r   r(   r%  )r)   s   "r*   r+   r+     s-      u 3 cDj Tb r,   c          	        V P                  WR7      pVP                  ;'       g    / pVP                  \        4      pVe   VP                  \        4      \
        8w  d   \        RV R24      hVP                  P                  R8w  d'   \        RV RVP                  P                   R24      h\        P                  VV\        \        V 4      V4      V \        P                  ^,           R7      # )	z?Reattach to a running host job and return its server transport.rl  r  z is not a sandbox host.r  zSandbox host r  rt  r  )rw  r  r  r  r  r  r   rx  ry  r%  rL  r4   r:  r   r   )r.  r  rm  rD  r  r%   s   &&$   r*   r  r    s    
///
BCZZ2FJJ{#E}

:.);T+.EFGG
zz9$];-7PQTQ[Q[QaQaPbbdeff""+,<S,A5I$99A= #  r,   c          	      z    V ^8  d   QhR\         R\         R,          R\        \         \         R,          3,          /# )r#   r  rm  Nr&   )r(   r   )r)   s   "r*   r+   r+     s3     * *# *#* *sCRVJAW *r,   c                    RV 9  d   W3# V P                  R^4      w  r#V'       d   V'       d   RV9   d   \        RV : R24      hVe   W8w  d   \        RV: RV: R24      hW23# )zPAccept `namespace/sandbox_id` ids (as shown in the Hub UI), like `hf jobs` does.r  z?Sandbox id must be 'sandbox_id' or 'namespace/sandbox_id', got r!   z%Conflicting namespace: got namespace=z" but sandbox id implies namespace=)r  r   )r  rm  extracted_namespace	parsed_ids   &&  r*   r  r    s    
*$$%/%5%5c1%="i3)3C\]g\jjklmm!A3I=@bcvbyyz{
 	
 ))r,   c                0    V ^8  d   QhR\         R\        /# )r#   rD  r&   )r   r(   )r)   s   "r*   r+   r+     s     g g' gc gr,   c                     V P                   P                  ;'       g    .  F  pR \         R2V9   g   K  Vu # 	  \        RV P                   R\         R24      h)z--r!   r  z) does not expose the sandbox server port )rx  expose_urlsr  r   rG  )rD  urls   & r*   rJ  rJ    s]    zz%%+++#$A&#-J , cffX%NObNccde
ffr,   limitc          
      b    V ^8  d   QhR\         R\        R\        R,          R\        R\        /# )r#   r.  r)  rm  Nr  r&   )r   r(   r7   )r)   s   "r*   r+   r+     s<     W W Ws W#* WTW Wad Wr,   c                     \        V P                  WR 7      4      V) R pT'       d    RRP                  R T 4       4      ,           # R#   \         d     R# i ; i)rl  Nr{   z Last logs:

c              3   ,   "   T F
  pR V 2x  K  	  R# 5i)z  NrZ   )rz  r  s   & r*   r{  !_tail_job_logs.<locals>.<genexpr>  s     &EutD6{us   )r   fetch_job_logsr   r   )r.  r)  rm  r  liness   &&$$ r*   r{  r{    sb    S''v'KLeVWU JO?TYY&Eu&EEEVTVV  s   A
 
AAiX  )	COMPLETEDERRORDELETEDCANCELED)Vr1   r.   r   r9  ru  concurrent.futuresr   
contextlibr   dataclassesr   r   pathlibr   r  r   typingr	   r
   r   r   r   r   r   r  r{   r   _sandbox_cacher   r   r   r   
_space_apir   errorsr   r   r   hf_apir   r   utilsr   r   utils._parsingr   
get_loggerr[   r  r  r  r  r  r  r  r  r)  r*  r  rN  r  rz  rj  r  r  r4   r;   r=   rf   rz   r   r  r  r#  r%  r  ru   r,  r:  r  rM  rL  r  r  rJ  r{  rZ   r,   r*   <module>r     s        1 % (   M M M     E E " % * 
		H	%   
	 
 !    A    ' 	 c$ s s s& C C C.   AN ANH	sxk xkv "{ {|^
 ^
B$6N	T 	4 $*gWt WZ\ W Wr,   