§
    ìXÊjã ã                   óŽ  — d dl Z d dlZd dlZd dlZd dlZd dlZd dlmZ d dlm	Z	 d dl
mZmZ d dlmZ d dlmZ d dlmZmZmZmZmZmZmZ d dlmZ d dlZd	d
lmZ d	dlmZm Z m!Z!m"Z"m#Z#m$Z$ d	dl%m&Z& d	dl'm(Z(m)Z)m*Z* d	dl+m,Z,m-Z- d	dl.m/Z/m0Z0 d	dl1m2Z2  e0j3        e4¦  «        Z5dZ6dZ7dZ8dZ9dZ:dZ;dZ< e=e7e8e;e<h¦  «        Z>dZ?dZ@dZAdZBdZCdZDdZEdZFd ZGd!ZHd"ZId#ZJd$ZKd%ZLd&ZMd'ZNd(ZOd)ePd*ePd+ePfd,„ZQd-eReSz  ePz  d+eRfd.„ZTe G d/„ d0¦  «        ¦   «         ZUe G d1„ d2¦  «        ¦   «         ZVe G d3„ d4¦  «        ¦   «         ZWe	d5ed+ee         fd6„¦   «         ZX G d7„ d8¦  «        ZYd9ePeeP         z  d:eZdz  d+e[ePef         fd;„Z\d<ej]        d+ee[         fd=„Z^d<ej]        d+dfd>„Z_d<ej]        d?ePd+dfd@„Z` G dA„ dBeja        ¦  «        ZbdCed+ePfdD„Zc G dE„ dF¦  «        Zd G dG„ dH¦  «        Ze G dI„ dJ¦  «        Zf G dK„ dL¦  «        ZgdMePdz  d+ePdz  fdN„ZhdOePd?ePd+ePdz  fdP„ZidQe-d+ePdz  fdR„ZjdSe!d+ePdz  fdT„ZkdUe,d"ePdz  d+e fdV„ZldWdXœdQe-dYePdZePdz  d"ePdz  dMePdz  d[ePdz  d\eZd+ePdz  fd]„ZmdUe,d+ePfd^„ZndUe,d)ePd_e[ePef         dz  d`e[ePef         dz  daee&         dz  dbeReSz  ePz  dz  dceZddePd+eoepeP         e[ePef         e[ePef         ee&         f         fde„Zqd+epeP         fdf„ZrdUe,dQe-d"ePdz  d+e[ePef         fdg„ZsdeHdhœdUe,diePd"ePdz  dYePd+e-f
dj„ZtddkœdUe,dlePd"ePdz  d+edfdm„ZudnePd"ePdz  d+eoePePdz  f         fdo„ZvdQe-d+ePfdp„ZwddqdrœdUe,d?ePd"ePdz  dseRd+ePf
dt„ZxdS )ué    N)ÚThreadPoolExecutor)Úcontextmanager)Ú	dataclassÚfield)ÚPath)Ú	token_hex)ÚAnyÚBinaryIOÚCallableÚIteratorÚListÚLiteralÚoverload)Úurlparseé   )Ú	constants)ÚHOST_TRUST_TTLÚCacheContextÚ
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.12z0.7.0Ú@eb2b04f79fbe765195300aaf1582be2a2a9ea698ff067d0cab428171d5584932é   iX  Ú24hé2   g      >@i   ÚownÚ	namespaceÚneverú.)Ú	COMPLETEDÚERRORÚDELETEDÚCANCELEDé   z/.hf-sbx-serveraÁ  set -e
d=/tmp/.sbx-server
if command -v wget >/dev/null 2>&1; then wget -q -O "$d" "$SBX_SERVER_URL"
elif command -v curl >/dev/null 2>&1; then curl -fsSL -o "$d" "$SBX_SERVER_URL"
else cp "$SBX_SERVER_MOUNT/sbx-server-$SBX_SERVER_SHA256" "$d"; fi
if command -v sha256sum >/dev/null 2>&1; then
  actual=$(sha256sum "$d" | cut -d' ' -f1)
elif command -v openssl >/dev/null 2>&1; then
  actual=$(openssl dgst -sha256 -r "$d" | cut -d' ' -f1)
elif [ "${SBX_ALLOW_UNVERIFIED_SERVER:-}" = 1 ]; then
  echo "sbx: SBX_ALLOW_UNVERIFIED_SERVER=1: running the sandbox server unverified" >&2
  actual=$SBX_SERVER_SHA256  # opted out, so there is nothing left to compare against
else
  echo "sbx: cannot verify the sandbox server digest: this image has neither sha256sum nor" >&2
  echo "sbx: openssl, so refusing to run it. Use an image with either hash tool installed." >&2
  echo "sbx: Dedicated jobs may opt out with env={'SBX_ALLOW_UNVERIFIED_SERVER': '1'};" >&2
  echo "sbx: pool hosts require setting it in the image environment instead." >&2
  exit 1
fi
if [ "$actual" != "$SBX_SERVER_SHA256" ]; then
  echo "sbx: sandbox server digest mismatch: got $actual," >&2
  echo "sbx: expected $SBX_SERVER_SHA256." >&2
  echo "sbx: refusing to run it. Upgrade huggingface_hub if this client is pinned to a" >&2
  echo "sbx: digest that is no longer published." >&2
  exit 1
fi
chmod +x "$d"
unset SBX_SERVER_URL SBX_SERVER_MOUNT SBX_SERVER_SHA256 SBX_ALLOW_UNVERIFIED_SERVER
exec "$d"
Úhf_tokenÚnonceÚreturnc                 ó´   — t          j        |                      ¦   «         d|› �                     ¦   «         t          j        ¦  «                             ¦   «         S )aO  Derive the sandbox auth token from the user's HF token and the job's 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.
    Only the derived token is passed to the sandbox server as a job secret; the HF token
    itself is not.

    Scope: one nonce is minted per *job*, not per sandbox. For a dedicated sandbox those are
    the same thing. In a pool this derives the *host* credential, which manages the pool and
    can recover per-sandbox tokens -- a leak there is host-wide. Each pooled sandbox also has
    its own random capability token, minted by the host server, which is what per-sandbox
    operations and `proxy_headers` use.

    This is not a hardened boundary in either direction. An untrusted image can own the
    sandbox port, so don't treat it as a guarantee that credentials stay out of the sandbox;
    and the token is derived for whichever job carries the matching nonce label, so don't
    treat holding it as proof of which job you are talking to.
    zhf-sandbox:)ÚhmacÚnewÚencodeÚhashlibÚsha256Ú	hexdigest)r1   r2   s     úIC:\Projects\Historical\venv\Lib\site-packages\huggingface_hub/_sandbox.pyÚ_derive_sandbox_tokenr<   ¡   sE   € õ& Œ8�H—O’OÑ%Ô%Ð'<°UÐ'<Ð'<×'CÒ'CÑ'EÔ'EÅwÄ~ÑVÔV×`Ò`ÑbÔbÐbó    Údurationc                 óv   — t          | t          t          f¦  «        rt          | ¦  «        S t          | ¦  «        S )zBParse a duration like 300, "300s", "10m", "2h", "1d" into seconds.)Ú
isinstanceÚintÚfloatr!   )r>   s    r;   Ú_duration_to_secsrC   ·   s2   € å�(�S¥%˜LÑ)Ô)ð Ý�8‰}Œ}ÐÝ˜(Ñ#Ô#Ð#r=   c                   ó�   — e Zd ZU dZedz  ed<   eed<   eed<   dZedz  ed<   dZe	ed<   d	Z
eed
<   ede	fd„¦   «         Zdefd„ZdS )ÚSandboxCommandResultz?Result of a command executed in a sandbox with [`Sandbox.run`].NÚ	exit_codeÚstdoutÚstderrÚsignalFÚ	timed_outr   Úduration_msr3   c                 ó   — | j         dk    S ©Nr   )rF   ©Úselfs    r;   ÚokzSandboxCommandResult.okÉ   s   € àŒ~ Ò"Ð"r=   c                 ó�   — t          | j        ¦  «        dk    r| j        n| j        d d…         dz   }d| j        › d|›d| j        › d�S )NéP   éM   z...zSandboxCommandResult(exit_code=z	, stdout=z, duration_ms=ú))ÚlenrG   rF   rK   )rO   Úouts     r;   Ú__repr__zSandboxCommandResult.__repr__Í   sX   € Ý  ¤Ñ-Ô-°Ò3Ð3ˆdŒkˆk¸¼ÀSÀbÀSÔ9IÈEÑ9QˆØr°´ÐrÐrÈ#ÐrÐrÐ_cÔ_oÐrÐrÐrÐrr=   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__rA   Ú__annotations__ÚstrrI   rJ   ÚboolrK   ÚpropertyrP   rW   © r=   r;   rE   rE   ¾   s¹   € € € € € € àIÐIà�T‰zÐÐÑØ€K€K�KØ€K€K�KØ€FˆC�$‰JÐÐÑØ€IˆtÐÐÑØ€K�ÐÐÑàð#�Dð #ð #ð #ñ „Xð#ðs˜#ð sð sð sð sð sð sr=   rE   c                   óÄ   — e Zd ZU dZedz  ed<   eed<   eee         z  ed<    edd¬¦  «        Z	ded	<   dZ
edz  ed
<   dZedz  ed<   dZeed<   dZedz  ed<   defd„ZdS )ÚSandboxProcessa�  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`].
    Recently completed processes stay in the listing (the server keeps a bounded number of
    them), so `running` and `exit_code` tell whether a process is still alive or already
    exited (as of when it was listed).
    NÚidÚpidÚcmdF)ÚreprÚcompareÚSandboxÚ_sandboxÚtagÚstarted_at_msTÚrunningrF   r3   c                 óÞ   — | j         €t          d¦  «        ‚| j                             dd| j         › �¦  «        }t	          |                     ¦   «                              dd¦  «        ¦  «        S )aŽ  Terminate the background process. Idempotent.

        Returns whether this call is what stopped it: `False` means it had already
        exited or been terminated, which is not an error.

        Note that a descendant which detaches with `setsid()` leaves the signalled
        process group and outlives this call. Delete the sandbox to be certain
        everything it started is gone.
        NzßThis process cannot be stopped individually: its sandbox runs a sandbox server that predates opaque process ids, so the server never issued one. Recycle the pool's hosts, or delete the sandbox to stop everything it started.ÚDELETEz/processes/ÚkilledF)rc   r   ri   Ú_requestr^   ÚjsonÚget)rO   Úresponses     r;   ÚkillzSandboxProcess.killë   sm   € ð Œ7ˆ?ÝðUñô ð ð
 ”=×)Ò)¨(Ð4KÀ$Ä'Ð4KÐ4KÑLÔLˆÝ�H—M’M‘O”O×'Ò'¨°%Ñ8Ô8Ñ9Ô9Ð9r=   )rX   rY   rZ   r[   r]   r\   rA   r   r   ri   rj   rk   rl   r^   rF   rt   r`   r=   r;   rb   rb   Ò   sÔ   € € € € € € ðð ð 	ˆd‰
€N€N�NØ	€H€H�HØ	ˆt�CŒy‰ÐÐÑð  ˜% U°EÐ:Ñ:Ô:€HˆiÐ:Ð:Ñ:Ø€Cˆˆt‰ÐÐÑØ $€M�3˜‘:Ð$Ð$Ñ$Ø€GˆTÐÐÑØ €Iˆs�T‰zÐ Ð Ñ ð:�dð :ð :ð :ð :ð :ð :r=   rb   c                   ój   — e Zd ZU dZeed<   eed<   ed         ed<   eed<   dZedz  ed<   d	Z	eed
<   dS )Ú	FileEntryz%A file or directory inside a sandbox.ÚnameÚpath)ÚfileÚdirÚsymlinkÚtypeÚsizeNÚmtime_msÚ Úmode)
rX   rY   rZ   r[   r]   r\   r   rA   r~   r€   r`   r=   r;   rv   rv   ÿ   sd   € € € € € € à/Ð/à
€I€I�IØ
€I€I�IØ
Ð*Ô
+Ð+Ð+Ñ+Ø
€I€I�IØ€Hˆc�D‰jÐÐÑØ€Dˆ#€N€N�N€N€Nr=   rv   Ú
local_pathc              #   óü  K  — | j         d| j        › dt          d¦  «        › d�z  }t          j        t          j        z  t          j        z  t          t          dd¦  «        z  t          t          dd¦  «        z  }t          j        ||d¦  «        }	 t          j	        |d¦  «        5 }|V — d	d	d	¦  «         n# 1 swxY w Y   t          j
        || ¦  «         d	S # t          $ r |                     d
¬¦  «         ‚ w xY w)a   Yield a writer whose bytes only appear at `local_path` once the download completes.

    Writing straight to the destination has three problems: an interrupted transfer leaves a
    truncated file at the final name; `open(path, "wb")` follows a symlink sitting there, so
    the sandbox's output can be redirected into any file this process can write; and a
    predictable temp name is a race another local process can win.

    So the bytes go to a temp file in the destination directory, created `O_EXCL` (nobody
    else's file) and `O_NOFOLLOW` (not a symlink) with mode `0600` and an unguessable name,
    then `os.replace`d into place. `rename` does not follow symlinks either, so a symlinked
    destination is *replaced* rather than written through, and a failure leaves nothing behind.
    r+   r0   z.partÚ
O_NOFOLLOWr   ÚO_BINARYi€  ÚwbNT)Ú
missing_ok)Úparentrw   r   ÚosÚO_WRONLYÚO_CREATÚO_EXCLÚgetattrÚopenÚfdopenÚreplaceÚBaseExceptionÚunlink)r�   ÚtmpÚflagsÚfdÚfs        r;   Ú_open_download_targetr–     s;  è è € ð Ô
ÐG *¤/ÐGÐGµI¸a±L´LÐGÐGÐGÑ
G€CÝŒK�"œ*Ñ$¥r¤yÑ0µ7½2¸|ÈQÑ3OÔ3OÑOÕRYÕZ\Ð^hÐjkÑRlÔRlÑl€EÝ	Œ��e˜UÑ	#Ô	#€BðÝŒY�r˜4Ñ Ô ð 	 AØˆGˆGˆGð	ð 	ð 	ñ 	ô 	ð 	ð 	ð 	ð 	ð 	ð 	øøøð 	ð 	ð 	ð 	å
Œ
�3˜
Ñ#Ô#Ð#Ð#Ð#øÝð ð ð Ø�
Š
˜dˆ
Ñ#Ô#Ð#Øðøøøs0   ÂC Â&B7Â+C Â7B;Â;C Â>B;Â?C Ã"C;c                   ó6  — e Zd ZdZdZdZdZdZd,d
„Zde	de
fd„Zd-de	de	de	fd„Zd.de	de	e
z  ez  de	d	z  dd	fd„Zd.de	ez  de	de	d	z  dd	fd„Zde	de	ez  dd	fd„Zdedeeeef                  fd„Zdee         deegef         dee         fd„Zde	dedede
fd„Zde	dedeeee
f                  fd„Zde	de
de	d	z  dd	fd„Zde	d edede	d	z  dd	f
d!„Zde	ded"e
de	d	z  d#edd	fd$„Zde	dee         fd%„Z de	defd&„Z!de	de"fd'„Z#d/de	d)e"dd	fd*„Z$de	dd	fd+„Z%d	S )0Ú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.

    Paths are normalized lexically, then resolved by the host server relative to an open
    home-directory descriptor. The file API refuses symlinks on every component, including
    links whose targets are inside the same home.
    i    é   é   i    Úsandboxrh   r3   Nc                 ó   — || _         d S ©N)ri   ©rO   r›   s     r;   Ú__init__zSandboxFiles.__init__?  s   € ØˆŒˆˆr=   rx   c                 ól  — |                       |¦  «        j        }|| j        k    rt          |› d|› d| j        › d�¦  «        ‚|| j        k    rQt          |¦  «        }|                      ||¦  «        D ]\  }}||||t          |¦  «        z   …<   Œt          |¦  «        S |  	                    |d|¦  «        S )zÝRead a file from the sandbox and return its content as bytes.

        Raises [`SandboxError`] above `MAX_READ_BYTES`; use [`download`] for
        anything that large, which streams to disk instead of buffering.
        z is z bytes, over the zc-byte limit for reading into memory. Use `files.download(path, local_path)`, which streams to disk.r   )
Ústatr}   ÚMAX_READ_BYTESr   ÚPARALLEL_THRESHOLDÚ	bytearrayÚ_read_rangesrU   ÚbytesÚ_read_range)rO   rx   r}   ÚbufferÚoffsetÚparts         r;   ÚreadzSandboxFiles.readB  së   € ð �yŠy˜‰ŒÔ#ˆØ�$Ô%Ò%Ð%ÝØð Yð Y˜Tð Yð Y°DÔ4Gð Yð Yð Yñô ð ð �$Ô)Ò)Ð)õ ˜t‘_”_ˆFØ $× 1Ò 1°$¸Ñ =Ô =ð ;ð ;‘�˜Ø6:��v ­¨T©¬Ñ 2Ð2Ñ3Ð3Ý˜‘=”=Ð Ø×Ò  a¨Ñ.Ô.Ð.r=   úutf-8Úencodingc                 óR   — |                       |¦  «                             |¦  «        S )z@Read a file from the sandbox and return its content as a string.)r«   Údecode)rO   rx   r­   s      r;   Ú	read_textzSandboxFiles.read_textW  s    € à�yŠy˜‰Œ×%Ò% hÑ/Ô/Ð/r=   Údatar€   c                 ó`  — t          |t          ¦  «        r|                     ¦   «         }n)t          |t          ¦  «        s|                     ¦   «         }t          |¦  «        | j        k    r|                      |||¦  «         dS d|i}|�||d<   | j         	                    dd||¬¦  «         dS )zHWrite content to a file in the sandbox (parent directories are created).Nrx   r€   ÚPUTú/files/write©ÚparamsÚcontent)
r@   r]   r7   r¦   r«   rU   r£   Ú_write_rangesri   rp   )rO   rx   r±   r€   r¶   s        r;   ÚwritezSandboxFiles.write[  s°   € å�d�CÑ Ô ð 	Ø—;’;‘=”=ˆDˆDÝ˜D¥%Ñ(Ô(ð 	Ø—9’9‘;”;ˆDÝˆt‰9Œ9�tÔ.Ò.Ð.Ø×Ò˜t T¨4Ñ0Ô0Ð0ØˆFØ˜$�ˆØÐØ!ˆF�6‰NØŒ×Ò˜u n¸VÈTÐÑRÔRÐRÐRÐRr=   r�   c                 ó&  — t          |d¦  «        5 }t          j        |                     ¦   «         ¦  «        j        }|| j        k    r|                      ||||¦  «         n|                      |||¬¦  «         ddd¦  «         dS # 1 swxY w Y   dS )a  Upload a local file to the sandbox.

        The file is opened once and both sized (`fstat`) and read through that same
        descriptor, so what is uploaded is the file that was measured -- rather than
        whatever the path resolves to a moment later.
        Úrb)r€   N)r�   rˆ   ÚfstatÚfilenoÚst_sizer£   Ú_write_ranges_from_filer¹   )rO   r�   rx   r€   r•   r}   s         r;   ÚuploadzSandboxFiles.uploadi  sÔ   € õ �*˜dÑ#Ô#ð 	/ qÝ”8˜AŸHšH™JœJÑ'Ô'Ô/ˆDØ�dÔ-Ò-Ð-ð ×,Ò,¨T°1°d¸DÑAÔAÐAÐAà—
’
˜4 ¨�
Ñ.Ô.Ð.ð	/ð 	/ð 	/ñ 	/ô 	/ð 	/ð 	/ð 	/ð 	/ð 	/ð 	/ð 	/øøøð 	/ð 	/ð 	/ð 	/ð 	/ð 	/s   ‘A(BÂB
ÂB
c                 ó.  — |                       |¦  «        j        }t          t          |¦  «        ¦  «        5 }|| j        k    rT|                      ||¦  «        D ]/\  }}|                     |¦  «         |                     |¦  «         Œ0	 ddd¦  «         dS | j         	                    ddd|i¬¦  «        5 }| 
                    d¬¦  «        D ]}|                     |¦  «         Œ	 ddd¦  «         n# 1 swxY w Y   ddd¦  «         dS # 1 swxY w Y   dS )a!  Download a file from the sandbox.

        The bytes land in a private temp file next to the destination and are renamed
        over it at the end, so an interrupted download leaves no truncated file and a
        symlink sitting at `local_path` is replaced rather than followed.
        NÚGETú/files/readrx   ©r¶   r™   ©Ú
chunk_size)r¡   r}   r–   r   r£   r¥   Úseekr¹   ri   Ú_streamÚ
iter_bytes)	rO   rx   r�   r}   r•   r©   rª   rs   Úchunks	            r;   ÚdownloadzSandboxFiles.downloadz  s·  € ð �yŠy˜‰ŒÔ#ˆÝ"¥4¨
Ñ#3Ô#3Ñ4Ô4ð 
	#¸Ø�dÔ-Ò-Ð-ð %)×$5Ò$5°d¸DÑ$AÔ$Að "ð "‘L�F˜DØ—F’F˜6‘N”N�NØ—G’G˜D‘M”M�M�MØð
	#ð 
	#ð 
	#ñ 
	#ô 
	#ð 
	#ð 
	#ð 
	#ð ”×&Ò& u¨mÀVÈTÀNÐ&ÑSÔSð #ÐW_Ø%×0Ò0¸KÐ0ÑHÔHð #ð #�EØ—G’G˜E‘N”N�N�Nð#ð#ð #ð #ñ #ô #ð #ð #ð #ð #ð #ð #øøøð #ð #ð #ð #ð
	#ð 
	#ð 
	#ñ 
	#ô 
	#ð 
	#ð 
	#ð 
	#ð 
	#ð 
	#ð 
	#ð 
	#øøøð 
	#ð 
	#ð 
	#ð 
	#ð 
	#ð 
	#s<   ·AD
ÂD
Â6/C2Ã&D
Ã2C6	Ã6D
Ã9C6	Ã:D
Ä
DÄDr}   c                 óP   ‡‡— | j         Šˆˆfd„t          d‰‰¦  «        D ¦   «         S )Nc                 ó:   •— g | ]}|t          ‰‰|z
  ¦  «        f‘ŒS r`   )Úmin)Ú.0r©   rÊ   r}   s     €€r;   ú
<listcomp>z(SandboxFiles._ranges.<locals>.<listcomp>�  s,   ø€ ÐXÐXÐX¸��˜U D¨6¡MÑ2Ô2Ð3ÐXÐXÐXr=   r   )ÚPARALLEL_CHUNK_SIZEÚrange)rO   r}   rÊ   s    `@r;   Ú_rangeszSandboxFiles._rangesŽ  s6   øø€ ØÔ(ˆØXÐXÐXÐXÐXÅ%ÈÈ4ÐQVÑBWÔBWÐXÑXÔXÐXr=   ÚitemsÚfnc                 óÞ   — t          | j        t          |¦  «        ¦  «        }t          |¦  «        5 }t	          |                     ||¦  «        ¦  «        cddd¦  «         S # 1 swxY w Y   dS )zÚRun `fn(item)` over items concurrently.

        All workers share the sandbox's `httpx2.Client`, which is thread-safe and pools
        connections, so parallel transfers fan out over several streams at once.
        N)rÎ   ÚPARALLEL_MAX_WORKERSrU   r   ÚlistÚmap)rO   rÔ   rÕ   ÚworkersÚexecutors        r;   Ú	_parallelzSandboxFiles._parallel’  s¤   € õ �dÔ/µ°U±´Ñ<Ô<ˆÝ Ñ(Ô(ð 	1¨HÝ˜Ÿš R¨Ñ/Ô/Ñ0Ô0ð	1ð 	1ð 	1ð 	1ñ 	1ô 	1ð 	1ð 	1ð 	1ð 	1ð 	1ð 	1øøøð 	1ð 	1ð 	1ð 	1ð 	1ð 	1s   ²#A"Á"A&Á)A&r©   Úlengthc                 ó´  — t          ¦   «         }| j                             dd|||dœ¬¦  «        5 }|                     d¬¦  «        D ]I}t	          |¦  «        t	          |¦  «        z   |k    rt          d¦  «        ‚|                     |¦  «         ŒJ	 d d d ¦  «         n# 1 swxY w Y   t	          |¦  «        |k    rt          d¦  «        ‚t          |¦  «        S )	NrÂ   rÃ   )rx   r©   rÝ   rÄ   r™   rÅ   z+File response exceeded the requested range.z6File changed size during transfer; retry the download.)r¤   ri   rÈ   rÉ   rU   r   Úextendr¦   )rO   rx   r©   rÝ   r±   rs   rÊ   s          r;   r§   zSandboxFiles._read_rangeœ  s   € Ý‰{Œ{ˆØŒ]×"Ò"Ø�=°$À&ÐTZÐ)[Ð)[ð #ñ 
ô 
ð 	#àØ!×,Ò,¸Ð,ÑDÔDð #ð #�Ý�t‘9”9�s 5™zœzÑ)¨FÒ2Ð2Ý&Ð'TÑUÔUÐUØ—’˜EÑ"Ô"Ð"Ð"ð#ð	#ð 	#ð 	#ñ 	#ô 	#ð 	#ð 	#ð 	#ð 	#ð 	#ð 	#øøøð 	#ð 	#ð 	#ð 	#õ ˆt‰9Œ9˜ÒÐÝÐWÑXÔXÐXÝ�T‰{Œ{Ðs   °A!BÂB"Â%B"c           	   #   óÐ  ‡ ‡K  — dt           t          t          f         dt           t          t          f         fˆˆ fd„}‰                      |¦  «        }t	          ‰ j        t          |¦  «        ¦  «        }t          |¦  «        5 }t          dt          |¦  «        |¦  «        D ])}| 	                    |||||z   …         ¦  «        E d{V —† Œ*	 ddd¦  «         dS # 1 swxY w Y   dS )a  Fetch every range in parallel, yielding `(offset, bytes)` as they land.

        Yielding rather than returning a list is the point: the caller places each
        chunk and drops it, so peak memory is a few chunks instead of the whole
        file plus a copy.
        Úrngr3   c                 ó@   •— | \  }}|‰                      ‰||¦  «        fS r�   )r§   )rá   r©   rÝ   rx   rO   s      €€r;   Úfetchz(SandboxFiles._read_ranges.<locals>.fetch±  s)   ø€ Ø ‰NˆF�FØ˜4×+Ò+¨D°&¸&ÑAÔAÐAÐAr=   r   N)
ÚtuplerA   r¦   rÓ   rÎ   r×   rU   r   rÒ   rÙ   )rO   rx   r}   rã   ÚrangesrÚ   rÛ   Ústarts   ``      r;   r¥   zSandboxFiles._read_ranges©  s`  øøè è € ð	B•u�S¥#˜X”ð 	B­5µµe°Ô+<ð 	Bð 	Bð 	Bð 	Bð 	Bð 	Bð 	Bð —’˜dÑ#Ô#ˆÝ�dÔ/µ°V±´Ñ=Ô=ˆÝ Ñ(Ô(ð 	P¨HÝ˜q¥# f¡+¤+¨wÑ7Ô7ð Pð P�Ø#Ÿ<š<¨¨v°e¸eÀg¹oÐ6MÔ/NÑOÔOÐOÐOÐOÐOÐOÐOÐOÐOðPð	Pð 	Pð 	Pñ 	Pô 	Pð 	Pð 	Pð 	Pð 	Pð 	Pð 	Pð 	Pøøøð 	Pð 	Pð 	Pð 	Pð 	Pð 	Ps   ÂA	CÃCÃ"Cc                 óÂ   ‡ ‡‡‡— dt           t          t          f         dd fˆˆˆˆ fd„}‰                      ‰                      t	          ‰¦  «        ¦  «        |¦  «         d S )Nrá   r3   c           	      óv   •— | \  }}‰                      ‰|‰|||z   …         ‰t          ‰¦  «        ¬¦  «         d S )N©Útotal)Ú
_put_rangerU   )rá   r©   rÝ   r±   r€   rx   rO   s      €€€€r;   Úpushz(SandboxFiles._write_ranges.<locals>.push¼  sF   ø€ Ø ‰NˆF�FØ�OŠO˜D &¨$¨v¸À¹Ð/GÔ*HÈ$ÕVYÐZ^ÑV_ÔV_ˆOÑ`Ô`Ð`Ð`Ð`r=   )rä   rA   rÜ   rÓ   rU   )rO   rx   r±   r€   rì   s   ```` r;   r¸   zSandboxFiles._write_ranges»  s‚   øøøø€ ð	a•e�C¥˜H”oð 	a¨$ð 	að 	að 	að 	að 	að 	að 	að 	að 	að 	�Š�t—|’|¥C¨¡I¤IÑ.Ô.°Ñ5Ô5Ð5Ð5Ð5r=   Úsourcec                 óÖ   ‡ ‡‡‡‡‡— t          j        ¦   «         Šdt          t          t          f         ddfˆˆˆˆ ˆˆfd„}‰                      ‰                      ‰¦  «        |¦  «         dS )z�Upload `source` in parallel ranges, reading each range on demand.

        Serialize reads from the shared descriptor; network writes still overlap.
        rá   r3   Nc                 ó  •— | \  }}‰5  ‰	                      |¦  «         ‰	                     |¦  «        }d d d ¦  «         n# 1 swxY w Y   t          |¦  «        |k    rt          d¦  «        ‚‰                     ‰||‰‰¬¦  «         d S )Nz+Upload source changed size during transfer.ré   )rÇ   r«   rU   r   rë   )
rá   r©   rÝ   rÊ   r€   rx   Ú	read_lockrO   r}   rí   s
       €€€€€€r;   rì   z2SandboxFiles._write_ranges_from_file.<locals>.pushÉ  sÎ   ø€ Ø ‰NˆF�FØð ,ð ,Ø—’˜FÑ#Ô#Ð#ØŸš FÑ+Ô+�ð,ð ,ð ,ñ ,ô ,ð ,ð ,ð ,ð ,ð ,ð ,øøøð ,ð ,ð ,ð ,õ �5‰zŒz˜VÒ#Ð#Ý"Ð#PÑQÔQÐQØ�OŠO˜D &¨%°¸TˆOÑBÔBÐBÐBÐBs   ‰+A Á AÁA)Ú	threadingÚLockrä   rA   rÜ   rÓ   )rO   rx   rí   r}   r€   rì   rð   s   ````` @r;   r¿   z$SandboxFiles._write_ranges_from_fileÂ  s™   øøøøøø€ õ
 ”NÑ$Ô$ˆ	ð	C•e�C¥˜H”oð 	C¨$ð 	Cð 	Cð 	Cð 	Cð 	Cð 	Cð 	Cð 	Cð 	Cð 	Cð 	Cð 	�Š�t—|’| DÑ)Ô)¨4Ñ0Ô0Ð0Ð0Ð0r=   rÊ   rê   c                ó�   — ||dœ}|�||d<   |t          |¦  «        z   |k    r||d<   | j                             dd||¬¦  «         d S )N)rx   r©   r€   Útruncate_tor³   r´   rµ   )rU   ri   rp   )rO   rx   r©   rÊ   r€   rê   r¶   s          r;   rë   zSandboxFiles._put_rangeÔ  se   € Ø*.¸&Ð!AÐ!AˆØÐØ!ˆF�6‰Nð •C˜‘J”JÑ %Ò'Ð'Ø$)ˆF�=Ñ!ØŒ×Ò˜u n¸VÈUÐÑSÔSÐSÐSÐSr=   c                 óþ   — g }d}	 d|i}|�||d<   | j                              dd|¬¦  «                             ¦   «         }|                     d„ |d	         D ¦   «         ¦  «         |                     d
¦  «        }|s|S Œy)zÜList a directory in the sandbox.

        The server paginates, so this follows the cursor and returns everything --
        a caller sees one list regardless of how the directory is chunked on the
        wire.
        NTrx   ÚafterrÂ   z/files/listrÄ   c              3   ó.   K  — | ]}t          di |¤ŽV — Œd S )Nr`   )rv   )rÏ   Úentrys     r;   ú	<genexpr>z$SandboxFiles.list.<locals>.<genexpr>í  s0   è è € ÐNÐN°%�9Ð-Ð- uÐ-Ð-ÐNÐNÐNÐNÐNÐNr=   ÚentriesÚnext)ri   rp   rq   rß   rr   )rO   rx   rú   rö   r¶   Úpayloads         r;   rØ   zSandboxFiles.listß  sœ   € ð $&ˆØ ˆð	Ø&,¨d ^ˆFØÐ Ø"'��w‘Ø”m×,Ò,¨U°MÈ&Ð,ÑQÔQ×VÒVÑXÔXˆGØ�NŠNÐNÐN¸7À9Ô;MÐNÑNÔNÑNÔNÐNØ—K’K Ñ'Ô'ˆEØð Ø�ð	r=   c                 ó|   — | j                              ddd|i¬¦  «        }t          di |                     ¦   «         ¤ŽS )z3Get metadata of a file or directory in the sandbox.rÂ   z/files/statrx   rÄ   r`   )ri   rp   rv   rq   )rO   rx   rs   s      r;   r¡   zSandboxFiles.statò  s?   € à”=×)Ò)¨%°ÈÐPTÀ~Ð)ÑVÔVˆÝÐ+Ð+˜8Ÿ=š=™?œ?Ð+Ð+Ð+r=   c                 óz   — 	 |                       |¦  «         dS # t          $ r}|j        dk    rY d}~dS ‚ d}~ww xY w)z+Check whether a path exists in the sandbox.Té”  NF)r¡   r   Ústatus_code)rO   rx   Úes      r;   ÚexistszSandboxFiles.exists÷  sW   € ð	Ø�IŠI�d‰OŒOˆOØ�4øÝð 	ð 	ð 	ØŒ} Ò#Ð#Ø�u�u�u�u�uØøøøøð	øøøs   ‚ ™
:£5´5µ:FÚ	recursivec                 óV   — d|i}|rd|d<   | j                              dd|¬¦  «         dS )z*Delete a file or directory in the sandbox.rx   Ú1r  rn   z/files/deleterÄ   N©ri   rp   )rO   rx   r  r¶   s       r;   ÚdeletezSandboxFiles.delete  s@   € à˜$�ˆØð 	&Ø"%ˆF�;ÑØŒ×Ò˜x¨ÀÐÑHÔHÐHÐHÐHr=   c                 óD   — | j                              ddd|i¬¦  «         dS )z0Create a directory (and parents) in the sandbox.ÚPOSTz/files/mkdirrx   rÄ   Nr  )rO   rx   s     r;   ÚmkdirzSandboxFiles.mkdir  s)   € àŒ×Ò˜v ~¸vÀt¸nÐÑMÔMÐMÐMÐMr=   )r›   rh   r3   N)r¬   r�   )F)&rX   rY   rZ   r[   r£   rÑ   r×   r¢   rŸ   r]   r¦   r«   r°   r
   r¹   r   rÀ   rË   rA   r   rä   rÓ   r	   r   rÜ   r§   r   r¥   r¸   r¿   rë   rv   rØ   r¡   r^   r  r  r
  r`   r=   r;   r˜   r˜   %  s¾  € € € € € ð	ð 	ð )ÐØ)ÐØÐð '€Nð ð  ð  ð  ð/˜ð / ð /ð /ð /ð /ð*0ð 0˜cð 0¨Sð 0¸sð 0ð 0ð 0ð 0ðSð S˜#ð S S¨5¡[°8Ñ%;ð SÀ3ÈÁ:ð SÐY]ð Sð Sð Sð Sð/ð /  t¡ð /°3ð /¸cÀD¹jð /ÐTXð /ð /ð /ð /ð"#˜Sð #¨c°D©jð #¸Tð #ð #ð #ð #ð(Y˜Cð Y D¨¨s°C¨x¬Ô$9ð Yð Yð Yð Yð1˜t Cœyð 1¨h¸°u¸c°zÔ.Bð 1ÀtÈCÄyð 1ð 1ð 1ð 1ð ð ¨Sð ¸#ð À%ð ð ð ð ðP ð P¨Cð P°H¸UÀ3ÈÀ:Ô=NÔ4Oð Pð Pð Pð Pð$6 #ð 6¨Uð 6¸#À¹*ð 6Èð 6ð 6ð 6ð 6ð1¨Cð 1¸ð 1Èð 1ÐTWÐZ^ÑT^ð 1Ðcgð 1ð 1ð 1ð 1ð$	T˜sð 	T¨Cð 	T¸ð 	TÀSÈ4ÁZð 	TÐ[^ð 	TÐcgð 	Tð 	Tð 	Tð 	Tð˜ð   i¤ð ð ð ð ð&,˜ð , ð ,ð ,ð ,ð ,ð
˜3ð  4ð ð ð ð ðIð I˜3ð I¨4ð I¸Dð Ið Ið Ið IðN˜#ð N $ð Nð Nð Nð Nð Nð Nr=   r˜   re   Úshellc                 ó¼   — |du r$t          | t          ¦  «        st          d¦  «        ‚|du r$t          | t          ¦  «        rt          d¦  «        ‚d| i}|�||d<   |S )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.re   Nr  )r@   r]   Ú
ValueError)re   r  rü   s      r;   Ú_exec_payloadr    sl   € à�€}€}�Z¨­SÑ1Ô1€}ÝÐ^Ñ_Ô_Ð_Ø�€~€~�* S­#Ñ.Ô.€~ÝÐmÑnÔnÐnØ$ c˜l€GØÐØ ˆ�ÑØ€Nr=   rs   c              #   ó    K  — |                       ¦   «         D ]6}|sŒt          j        |¦  «        }|                     d¦  «        dk    r|V — Œ7dS )zJIterate NDJSON events from a streaming response, skipping keepalive pings.ÚeventÚpingN)Ú
iter_linesrq   Úloadsrr   )rs   Úliner  s      r;   Ú_iter_eventsr    sf   è è € à×#Ò#Ñ%Ô%ð ð ˆØð 	ØÝ”
˜4Ñ Ô ˆØ�9Š9�WÑÔ Ò'Ð'ØˆKˆKˆKøðð r=   c                 óâ   — |                       ¦   «          	 |                      ¦   «         d         }n# t          $ r | j        dd…         }Y nw xY wt	          d| j        › d|› �| j        ¬¦  «        ‚)zQRead the error body and raise a SandboxError (works for streaming responses too).ÚerrorNiô  zSandbox API error (z): )r   )r«   rq   Ú	ExceptionÚtextr   r   )rs   Úmessages     r;   Ú_raise_for_statusr  #  s‚   € à‡M‚M�O„O€Oð&Ø—-’-‘/”/ 'Ô*ˆˆøÝð &ð &ð &Ø”-   Ô%ˆˆˆð&øøøå
ÐO¨XÔ-AÐOÐOÀgÐOÐOÐ]eÔ]qÐ
rÑ
rÔ
rÐrs   –1 ±AÁAÚjob_idc           	      ó.  — 	 |                       ¦   «                              d¦  «        }n# t          $ r d}Y nw xY wt          |t          ¦  «        r"t          |t
          ¦  «        s|t          k    rdS |�|nd}t          d|› d|› dt          › d�¦  «        ‚)a  Refuse a server whose wire contract this client cannot drive.

    Permissive in one direction only. A *newer* server is accepted: it declares its own
    backwards compatibility by keeping the protocol integer it still supports. An *older* one
    is refused, because the mismatches are things like the per-sandbox capability token, which
    surfaces as a 403 on an unrelated route several calls later instead of here.

    `version` is no use for this: it moves for a doc fix as readily as for a protocol break.
    ÚprotocolNz1 (declares no protocol)úSandbox job z runs sbx-server protocol z5, but this version of huggingface_hub needs protocol z¶ or newer. A pool host keeps the server binary it downloaded at boot for up to 24h, so recycle this pool's hosts (kill them, or let them idle-time-out) to pick up the current server.)rq   rr   r  r@   rA   r^   ÚSANDBOX_SERVER_PROTOCOLr   )rs   r  r  Úreporteds       r;   Ú_check_server_protocolr"  -  sÓ   € ðØ—=’=‘?”?×&Ò& zÑ2Ô2ˆˆøÝð ð ð Øˆˆˆðøøøå�(�CÑ Ô ð ­°H½dÑ)CÔ)Cð ÈÕTkÒHkÐHkØˆà#Ð/ˆxˆxÐ5O€HÝ
ð	D�vð 	Dð 	D¸ð 	Dð 	DÝ*Að	Dð 	Dð 	Dñô ð s   ‚'* ª9¸9c                   ó(   — e Zd ZdZdeddfd„Zd„ ZdS )Ú_SandboxAuthaþ  Attach the *current* HF bearer to every request.

    The bearer used to be captured once when the transport was built. A sandbox
    host lives up to 24h, so an OIDC/OAuth credential can expire or rotate inside
    that window, after which every request to the Jobs proxy failed even though
    the handle was still perfectly good. Reading it per request fixes that.

    The `X-Sandbox-Token` is deliberately *not* re-derived: the server holds the
    value derived from the bearer that created the job, so re-deriving from a
    rotated bearer would produce a token the server has never seen. The two
    credentials answer different gates -- the proxy wants a live bearer, the
    server wants the original capability -- and only the first needs refreshing.
    Úapir3   Nc                 ó   — || _         d S r�   )Ú_api)rO   r%  s     r;   rŸ   z_SandboxAuth.__init__V  s   € ØˆŒ	ˆ	ˆ	r=   c              #   óP   K  — dt          | j        ¦  «        › �|j        d<   |V — d S )NúBearer ÚAuthorization)Ú_effective_tokenr'  Úheaders)rO   Úrequests     r;   Ú	auth_flowz_SandboxAuth.auth_flowY  s2   è è € Ø+RÕ5EÀdÄiÑ5PÔ5PÐ+RÐ+RˆŒ˜Ñ(Øˆˆˆˆˆr=   )rX   rY   rZ   r[   r   rŸ   r.  r`   r=   r;   r$  r$  G  sO   € € € € € ðð ð˜Eð  dð ð ð ð ðð ð ð ð r=   r$  Útokenc                 óR   — t          | t          ¦  «        r| st          d¦  «        ‚| S )Nz\The pool host returned no valid sandbox-scoped token; recycle it with an updated sbx-server.)r@   r]   r   ©r/  s    r;   Ú_require_scoped_tokenr2  ^  s7   € Ý�e�SÑ!Ô!ð 
¨ð 
ÝØjñ
ô 
ð 	
ð €Lr=   c                   óp  — e Zd ZdZdddœdedededz  d	ed
edededededdfd„Zedddœde	d
edededededd fd„¦   «         Z
ededz  fd„¦   «         Zdededz  defd„Zddœdedededz  dej        fd„Zeddœdedededz  deej                 fd„¦   «         Zdedefd„Zd!d„Zd!d„Zdeddfd „ZdS )"Ú_SandboxServeruF  HTTP transport to one `sbx-server` instance â€” a dedicated job or a shared host.

    Owns the `httpx2.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.
    é
   r   )Úmax_connectionsÚcapacityr  ÚownerÚimageNÚbase_urlr2   Úsandbox_tokenr%  r6  r7  r3   c       	         ó   — || _         || _        || _        || _        || _        || _        || _        |	| _        d| _        d| _	        d| _
        t          j        d|it          |¦  «        t          j        ||¬¦  «        d¬¦  «        | _        d S )Nr   TFúX-Sandbox-Token)r6  Úmax_keepalive_connections)r,  ÚauthÚlimitsÚfollow_redirects)r  r8  Ú_imager:  r2   r'  Ú_sandbox_tokenr7  ÚliveÚverifiedÚownedÚhttpx2ÚClientr$  ÚLimitsÚ_client)
rO   r  r8  r9  r:  r2   r;  r%  r6  r7  s
             r;   rŸ   z_SandboxServer.__init__n  s¡   € ð ˆŒØˆŒ
ØˆŒØ ˆŒð ˆŒ
ØˆŒ	Ø+ˆÔà ˆŒØˆŒ	ð ˆŒð ˆŒ
õ ”}Ø&¨Ð6Ý˜cÑ"Ô"Ý”=°Ð\kÐlÑlÔlð
 #ð	
ñ 	
ô 	
ˆŒˆˆr=   Újobc                óz   —  | |j         |j        j        |j        p|j        t          |¦  «        |||||¬¦	  «	        S )zIBuild a server from a freshly fetched job (reads its exposed server URL).©	r  r8  r9  r:  r2   r;  r%  r6  r7  )rc   r8  rw   Údocker_imageÚspace_idÚ_find_server_url)ÚclsrK  r2   r;  r%  r6  r7  s          r;   Úfrom_jobz_SandboxServer.from_job�  sP   € ð ˆsØ”6Ø”)”.ØÔ"Ð2 c¤lÝ% cÑ*Ô*ØØ'ØØ+Øð

ñ 

ô 

ð 
	
r=   c                 ó   — | j         S r�   )rB  rN   s    r;   r9  z_SandboxServer.imageµ  s
   € àŒ{Ðr=   Úkwargsc                 óH   — |�i |                      di ¦  «        ¥d|i¥|d<   |S )aB  Override `X-Sandbox-Token` for one request.

        The client-level header carries the *host* credential, which manages the
        pool. A pooled sandbox's own operations should present that sandbox's
        capability token instead, so nothing wider than the sandbox is offered on
        a per-sandbox call.
        Nr,  r=  )rr   )rO   rT  r;  s      r;   Ú_with_tokenz_SandboxServer._with_token¹  s8   € ð Ð$Ø _ 6§:¢:¨i¸Ñ#<Ô#<Ð _Ð>OÐQ^Ð _Ð _ˆF�9ÑØˆr=   ©r;  Úmethodrx   c                óö   — |                      dt          j        dd¬¦  «        ¦  «        }|                      ||¦  «        } | j        j        || j        |z   fd|i|¤Ž}|j        dk    rt          |¦  «         |S )z@Request to the in-job server. Raises SandboxError on API errors.Útimeoutg      N@ç      $@©Úconnecté�  )	ÚpoprG  ÚTimeoutrV  rJ  r-  r:  r   r  ©rO   rX  rx   r;  rT  rZ  rs   s          r;   r-  z_SandboxServer.requestÅ  s…   € à—*’*˜Y­¬°tÀTÐ(JÑ(JÔ(JÑKÔKˆØ×!Ò! &¨-Ñ8Ô8ˆØ'�4”<Ô'¨°´ÀÑ0DÐ`Ð`ÈgÐ`ÐY_Ð`Ð`ˆØÔ 3Ò&Ð&Ý˜hÑ'Ô'Ð'Øˆr=   c             +   ó4  K  — |                      dt          j        dd¬¦  «        ¦  «        }|                      ||¦  «        } | j        j        || j        |z   fd|i|¤Ž5 }|j        dk    rt          |¦  «         |V — ddd¦  «         dS # 1 swxY w Y   dS )zJStreaming request to the in-job server. Raises SandboxError on API errors.rZ  g     €Q@r[  r\  r^  N)	r_  rG  r`  rV  rJ  Ústreamr:  r   r  ra  s          r;   rc  z_SandboxServer.streamÎ  sò   è è € ð
 —*’*˜Y­¬°tÀTÐ(JÑ(JÔ(JÑKÔKˆØ×!Ò! &¨-Ñ8Ô8ˆØ ˆTŒ\Ô  ¨¬¸Ñ)=ÐYÐYÀwÐYÐRXÐYÐYð 	Ð]eØÔ# sÒ*Ð*Ý! (Ñ+Ô+Ð+ØˆNˆNˆNð	ð 	ð 	ñ 	ô 	ð 	ð 	ð 	ð 	ð 	ð 	ð 	øøøð 	ð 	ð 	ð 	ð 	ð 	s   Á!BÂBÂBÚlocal_idc                 óž   — |                       dd|› d�¦  «                             ¦   «         }t          |                     d¦  «        ¦  «        S )zKRecover a pooled sandbox's capability using the host management credential.rÂ   ú/v1/sandboxes/z/tokenr/  )r-  rq   r2  rr   )rO   rd  r±   s      r;   r;  z_SandboxServer.sandbox_tokenÚ  sG   € à�|Š|˜EÐ#D°HÐ#DÐ#DÐ#DÑEÔE×JÒJÑLÔLˆÝ$ T§X¢X¨gÑ%6Ô%6Ñ7Ô7Ð7r=   c                 ó8   — | j                              ¦   «          d S r�   )rJ  ÚcloserN   s    r;   rh  z_SandboxServer.closeß  s   € ØŒ×ÒÑÔÐÐÐr=   c                 óR   — | j                              | j        | j        ¬¦  «         d S )N©r  r)   )r'  Ú
cancel_jobr  r8  rN   s    r;   rk  z_SandboxServer.cancel_jobâ  s'   € ØŒ	×Ò D¤K¸4¼:ÐÑFÔFÐFÐFÐFr=   Ústart_timeoutc           
      óF  — t          j         ¦   «         |z   }d}t          j         ¦   «         |k     �rV	 | j                             | j        dz   t	          j        d¦  «        ¬¦  «        }|j        dk    rt          || j        ¦  «         dS n# t          j	        $ r Y nw xY wt          j         ¦   «         |z
  dk    r¡t          j         ¦   «         }| j
                             | j        | j        ¬¦  «        }|j        j        t          v rUt!          | j
        | j        | j        ¬	¦  «        }t#          d
| j        › d|j        j        › d|j        j        › d|› �¦  «        ‚t          j        d¦  «         t          j         ¦   «         |k     �°Vt#          d
| j        › d|d›d�¦  «        ‚)zMPoll /health until the server answers; fail fast (with logs) if the job dies.g        z/healthg      @©rZ  éÈ   Ng       @rj  ©r)   r  z$ terminated during startup (status: z, message: ú).g333333Ã?z did not become ready within z.0fzs.)ÚtimerJ  rr   r:  rG  r`  r   r"  r  ÚRequestErrorr'  Úinspect_jobr8  ÚstatusÚstageÚ_TERMINAL_STAGESÚ_tail_job_logsr   r  Úsleep)rO   rl  ÚdeadlineÚlast_job_checkrs   rK  Úlogss          r;   Ú
wait_readyz_SandboxServer.wait_readyå  sÀ  € å”9‘;”; Ñ.ˆØˆÝŒi‰kŒk˜HÒ$Ñ$ðØœ<×+Ò+¨D¬M¸IÑ,EÍvÌ~Ð^aÑObÔObÐ+ÑcÔc�ØÔ'¨3Ò.Ð.Ý*¨8°T´[ÑAÔAÐAØ�Fð /øõ Ô&ð ð ð Ø�ðøøøåŒy‰{Œ{˜^Ñ+¨cÒ1Ð1Ý!%¤¡¤�Ø”i×+Ò+°4´;È$Ì*Ð+ÑUÔU�Ø”:Ô#Õ'7Ð7Ð7Ý)¨$¬)°T´[ÈDÌJÐWÑWÔW�DÝ&ð^ t¤{ð ^ð ^Ø$'¤JÔ$4ð^ð ^ØADÄÔASð^ð ^ØW[ð^ð ^ñô ð õ ŒJ�tÑÔÐõ# Œi‰kŒk˜HÒ$Ñ$õ$ Ði¨$¬+ÐiÐiÐTaÐiÐiÐiÐiÑjÔjÐjs   ²AB ÂBÂB©r3   N)rX   rY   rZ   r[   r]   r   rA   rŸ   Úclassmethodr   rR  r_   r9  ÚdictrV  rG  ÚResponser-  r   r   rc  r;  rh  rk  rB   r}  r`   r=   r;   r4  r4  f  s–  € € € € € ðð ð"  "Øð-
ð -
ð -
ð ð-
ð ð	-
ð
 �T‰zð-
ð ð-
ð ð-
ð ð-
ð ð-
ð ð-
ð ð-
ð 
ð-
ð -
ð -
ð -
ð^ ð  "Øð
ð 
ð 
ð ð
ð ð	
ð
 ð
ð ð
ð ð
ð ð
ð 
ð
ð 
ð 
ñ „[ð
ð. ð�s˜T‘zð ð ð ñ „Xðð
 $ð 
°s¸T±zð 
Àdð 
ð 
ð 
ð 
ð NRð ð ð ˜cð ¨ð ÀÀdÁ
ð Ð`fÔ`oð ð ð ð ð àEIð	ð 	ð 	Øð	Ø!$ð	Ø8;¸d¹
ð	à	�&”/Ô	"ð	ð 	ð 	ñ „^ð	ð8 cð 8¨cð 8ð 8ð 8ð 8ð
ð ð ð ðGð Gð Gð Gðk¨ð k°$ð kð kð kð kð kð kr=   r4  c            	       ó–   — e Zd ZdZedddeded         fd„¦   «         Zedddedeg df         fd	„¦   «         Zdd
deded         fd„ZdS )Ú_KillMethodz>Lets `kill` work both as a classmethod and an instance method.ÚinstanceNr8  r3   ).Nc                 ó   — d S r�   r`   ©rO   r„  r8  s      r;   Ú__get__z_KillMethod.__get__  s   € ØKNÈ3r=   rh   c                 ó   — d S r�   r`   r†  s      r;   r‡  z_KillMethod.__get__  s   € ØORÈsr=   úSandbox | Nonec           	      óh   ‡— |�|j         S d d dœdt          dt          d z  dt          d z  dd fˆfd„}|S )N©r)   r/  Ú
sandbox_idr)   r/  r3   c                ó\   •— ‰                      | ||¬¦  «                             ¦   «          d S )Nr‹  )r]  rt   )rŒ  r)   r/  r8  s      €r;   rt   z!_KillMethod.__get__.<locals>.kill	  s-   ø€ Ø�MŠM˜*°	ÀˆMÑGÔG×LÒLÑNÔNÐNÐNÐNr=   )Ú_killr]   )rO   r„  r8  rt   s     ` r;   r‡  z_KillMethod.__get__  sx   ø€ ØÐØ”>Ð!à=AÐW[ð 	Oð 	Oð 	O�Sð 	Oµ°d±
ð 	OÍ#ÐPTÉ*ð 	OÐ`dð 	Oð 	Oð 	Oð 	Oð 	Oð 	Oð ˆr=   )rX   rY   rZ   r[   r   r|   r   r‡  r`   r=   r;   rƒ  rƒ  þ  s¡   € € € € € ØHÐHàØN ÐN¨TÐN°h¸yÔ6IÐNÐNÐNñ „XØNØØR 	ÐR°$ÐR¸8ÀBÈÀHÔ;MÐRÐRÐRñ „XØRðÐ 0ð ¸ð À(È9ÔBUð ð ð ð ð ð r=   rƒ  c                   ó¼  — e Zd ZdZddœdedededz  deded	edz  d
dfd„Zee	fde
dddddddddœ
dededeez  ez  dz  deeef         dz  deeef         dz  dee         dz  dedz  dedeeef         dz  dededz  d
d fd„¦   «         Zedddœdededz  dedz  d
d fd„¦   «         Z e¦   «         ZdDd„ZdDd „ZdEd!„ZdDd"„Zed#d#d#d#d#d#d#d#d#d#d$œ
d%eee         z  d&edz  deeef         dz  d'edz  d(edz  d)edz  d*eegdf         dz  d+eegdf         dz  d,ed-ed.ed         d
efd/„¦   «         Zed#d#d#d0œd%eee         z  d&edz  deeef         dz  d'edz  d.ed1         d
efd2„¦   «         Zdddddddd1d1dd$œ
d%eee         z  d&edz  deeef         dz  d'edz  d(edz  d)edz  d*eegdf         dz  d+eegdf         dz  d,ed-ed.ed
eez  fd3„Zd
ee         fd4„Ze d
edz  fd5„¦   «         Z!e d
edz  fd6„¦   «         Z"dFd8d9œd:eez  d;ed<ed
efd=„Z#e d
eeef         fd>„¦   «         Z$d
efd?„Z%d@edAed
e&j'        fdB„Z(e)d@edAed
e*e&j'                 fdC„¦   «         Z+dS )Grh   aQ  An isolated cloud machine running on Hugging Face Jobs.

    > [!NOTE]
    > The Sandbox API is experimental. Its API and behavior may change without notice.

    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)
    ```
    NrW  rc   Úserverrd  Úowns_sandboxÚowns_serverr;  r3   c                óæ   — || _         || _        |€|j        nt          |¦  «        | _        || _        |€dnd|› �| _        || _        || _        d | _        d| _	        t          | ¦  «        | _        d S )Nz/v1rf  F)rc   Ú_serverrC  r2  Ú	_local_idÚ
_base_pathÚ_owns_sandboxÚ_owns_serverÚ_on_killÚ_killedr˜   Úfiles)rO   rc   r�  rd  r‘  r’  r;  s          r;   rŸ   zSandbox.__init__  s‹   € ð ˆŒØˆŒð 8@Ð7G˜fÔ3Ð3ÕMbÐcpÑMqÔMqˆÔà!ˆŒð $,Ð#3˜%˜%Ð9TÈ(Ð9TÐ9TˆŒð *ˆÔð (ˆÔà<@ˆŒØˆŒÝ! $Ñ'Ô'ˆŒ
ˆ
ˆ
r=   ú	cpu-basicFç      ^@)
ÚflavorÚidle_timeoutÚenvÚsecretsÚvolumesr)   Úforward_hf_tokenÚlabelsrl  r/  r9  rž  rŸ  r   r¡  r¢  r)   r£  r¤  rl  r/  c       
         óh  — |	�¨t          |	t          ¦  «        s$t          dt          |	¦  «        j        › �¦  «        ‚|	                     ¦   «         D ]Z\  }}t          |t          ¦  «        rt          |t          ¦  «        st          d¦  «        ‚|t          v rt          d|› d�¦  «        ‚Œ[t          |¬¦  «        }t          |¦  «        }t          d¦  «        }t          ||¦  «        }t          ||||||||¬¦  «        \  }}}}|                     |||||t          i |	pi ¥t          d	t           t"          t$          |i¥|pdt&          g|¬
¦
  «
        }d}	 t(                               ||||t,          j        dz   ¬¦  «        }|                     |
¦  «         n‰# t2          $ r| 	 |                     |j        |j        j        ¬¦  «         n<# t2          $ r/}t<                               d|j        › d|› �¦  «         Y d}~nd}~ww xY w|�|                      ¦   «          ‚ w xY w | |j        |ddd¬¦  «        S )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. Note that a
                *foreground* command is not currently counted as activity, so a single
                `run()` that takes longer than this without other API traffic can have its
                sandbox shut down under it â€” raise the timeout (or pass `None`) for long
                single commands.
            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).
            labels (`dict[str, str]`, *optional*):
                Labels to attach to the underlying HF Job.
            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).
        Nz'`labels` must be a dict[str, str], got z(`labels` keys and values must be stringszLabel 'zB' is reserved by huggingface_hub Sandbox and cannot be overridden.r1  rš   ©r   r¡  r¢  rŸ  r£  r;  r  ©
r9  Úcommandr   r¡  rž  rZ  r¤  r¢  Úexposer)   é   ©rK  r2   r;  r%  r6  rj  zFailed to cancel sandbox job ú after startup failure: T©rc   r�  rd  r‘  r’  )!r@   r€  r  r|   rX   rÔ   r]   ÚRESERVED_SANDBOX_LABELSr   r+  r   r<   Ú_bootstrap_job_specÚrun_jobÚSANDBOX_MAX_LIFETIMEÚSANDBOX_LABELÚ
MODE_LABELÚMODE_DEDICATEDÚNONCE_LABELÚSANDBOX_SERVER_PORTr4  rR  r˜   r×   r}  r  rk  rc   r8  rw   ÚloggerÚwarningrh  )rQ  r9  rž  rŸ  r   r¡  r¢  r)   r£  r¤  rl  r/  ÚkeyÚvaluer%  r1   r2   r;  r¨  Újob_envÚjob_secretsÚjob_volumesrK  r�  r  s                            r;   ÚcreatezSandbox.createC  sª  € ðt ÐÝ˜f¥dÑ+Ô+ð dÝ Ð!bÍ4ÐPVÉ<Ì<ÔK`Ð!bÐ!bÑcÔcÐcØ$Ÿlšl™nœnð xð x‘
��UÝ! #¥sÑ+Ô+ð Qµ:¸eÅSÑ3IÔ3Ið QÝ$Ð%OÑPÔPÐPØÕ1Ð1Ð1Ý$Ð%v¨sÐ%vÐ%vÐ%vÑwÔwÐwð 2õ ˜%Ð Ñ Ô ˆÝ# CÑ(Ô(ˆÝ˜"‘”ˆÝ-¨h¸Ñ>Ô>ˆå5HØØØØØØ%Ø-Ø'ð	6
ñ 	6
ô 	6
Ñ2ˆ�˜+ {ð �kŠkØØØØØÝ(Øi�v�| Ði¥m°S½*ÅnÕVaÐchÐiÐiØÐ' 4Ý'Ð(Øð ñ 
ô 
ˆð +/ˆð	Ý#×,Ò,ØØØ+ØÝ ,Ô AÀAÑ Eð -ñ ô ˆFð ×Ò˜mÑ,Ô,Ð,Ð,øÝð 		ð 		ð 		ðdØ—’ c¤f¸¼	¼�ÑGÔGÐGÐGøÝð dð dð dÝ—’Ðb¸s¼vÐbÐbÐ_`ÐbÐbÑcÔcÐcÐcÐcÐcÐcÐcøøøøðdøøøàÐ!Ø—’‘”�Øð		øøøð ˆs�c”f V°dÈÐ[_Ð`Ñ`Ô`Ð`s7   ÅAF Æ
HÆ!&GÇHÇ
HÇ%G<Ç7HÇ<HÈHr‹  rŒ  c                ój  — t          |¬¦  «        }t          ||¦  «        \  }}t          |v rÇ|                     t          d¦  «        \  }}t	          |||¬¦  «        }	 d„ |                     dd¦  «                             ¦   «         D ¦   «         }||vrt          d|› d|› d	�¦  «        ‚|                     |¦  «        }	n## t          $ r | 
                    ¦   «          ‚ w xY w | |||d
d|	¬¦  «        S |                     ||¬¦  «        }
|
j        pi }|                     t          ¦  «        }|                     t          ¦  «        dk    s|€t          d|› dt          › d�¦  «        ‚|                     t           ¦  «        t"          k    rt          d|› dt          › d�¦  «        ‚|
j        j        dk    r t          d|› d|
j        j        › d�¦  «        ‚t)          t+          |¦  «        |¦  «        }	t,                               |
||	|t0          j        dz   ¬¦  «        } | |
j        |dd
d¬¦  «        S )z?Reattach to a running sandbox from anywhere, using only its id.r1  r   rp  c                 ó   — h | ]
}|d          ’ŒS )rc   r`   )rÏ   Úitems     r;   ú	<setcomp>z"Sandbox.connect.<locals>.<setcomp>Á  s   € ÐaÐaÐa¨4˜D œJÐaÐaÐar=   rÂ   ú/v1/sandboxeszSandbox z no longer exists on host r+   FT©rc   r�  rd  r‘  r’  r;  rj  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: rq  rª  r«  r­  )r   Ú_split_sandbox_idÚSHARED_ID_SEPÚsplitÚ_connect_hostr-  rq   r   r;  r  rh  rt  r¤  rr   rµ  r²  r³  Ú	MODE_POOLru  rv  r<   r+  r4  rR  r˜   r×   rc   )rQ  rŒ  r)   r/  r%  Úhost_job_idrd  r�  Úexistingr;  rK  r¤  r2   s                r;   r]  zSandbox.connect¸  s•  € õ ˜%Ð Ñ Ô ˆÝ 1°*¸iÑ HÔ HÑˆ
�IÝ˜JÐ&Ð&Ø$.×$4Ò$4µ]ÀAÑ$FÔ$FÑ!ˆK˜Ý" 3¨¸yÐIÑIÔIˆFð	ØaÐa°6·>²>À%ÈÑ3YÔ3Y×3^Ò3^Ñ3`Ô3`ÐaÑaÔa�Ø 8Ð+Ð+Ý&Ð'f°*Ð'fÐ'fÐXcÐ'fÐ'fÐ'fÑgÔgÐgð !'× 4Ò 4°XÑ >Ô >��øÝð ð ð Ø—’‘”�Øðøøøð �3ØØØ!Ø"Ø Ø+ðñ ô ð ð �oŠo Z¸9ˆoÑEÔEˆØ”Ð!˜rˆØ—
’
�;Ñ'Ô'ˆØ�:Š:•mÑ$Ô$¨Ò+Ð+¨u¨}ÝÐf jÐfÐfÍmÐfÐfÐfÑgÔgÐgØ�:Š:•jÑ!Ô!¥YÒ.Ð.ÝðO�zð Oð OÝ3@ðOð Oð Oñô ð ð Œ:Ô˜yÒ(Ð(ÝÐc¨*ÐcÐcÈsÌzÔO_ÐcÐcÐcÑdÔdÐdÝ-Õ.>¸sÑ.CÔ.CÀUÑKÔKˆÝ×(Ò(ØØØ'ØÝ(Ô=ÀÑAð )ñ 
ô 
ˆð ˆs�c”f V°dÈÐ\`ÐaÑaÔaÐas   ÁA!C  Ã  C c                 ó¶  — | j         rdS 	 | j        €| j                             ¦   «          n*| j                             dd| j        › �| j        ¬¦  «         n=# t          $ r0}t                               d| j	        › d|› �¦  «         Y d}~dS d}~ww xY wd| _         | j
        �|  
                    | ¦  «         | j        r| j                             ¦   «          dS dS )zÉTerminate the sandbox. Idempotent.

        Dedicated sandboxes cancel their underlying job; shared sandboxes are
        removed from their host (freeing a slot) while the host keeps running.
        Nrn   rf  rW  zFailed to kill sandbox ú: T)rš  r•  r”  rk  r-  rC  r  r·  r¸  rc   r™  r˜  rh  ©rO   r  s     r;   rŽ  zSandbox._killí  s  € ð Œ<ð 	ØˆFð	ØŒ~Ð%Ø”×'Ò'Ñ)Ô)Ð)Ð)à”×$Ò$ XÐ/PÀÄÐ/PÐ/PÐ`dÔ`sÐ$ÑtÔtÐtøøÝð 	ð 	ð 	å�NŠNÐC°T´WÐCÐCÀÐCÐCÑDÔDÐDØˆFˆFˆFˆFˆFøøøøð	øøøð ˆŒØŒ=Ð$Ø�MŠM˜$ÑÔÐØÔð 	!ØŒL×ÒÑ Ô Ð Ð Ð ð	!ð 	!s   ‹AA Á
BÁ!%BÂBc                 óJ   — | j         r| j                             ¦   «          dS dS )zžRelease 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  rN   s    r;   rh  zSandbox.close  s3   € ð
 Ôð 	!ØŒL×ÒÑ Ô Ð Ð Ð ð	!ð 	!r=   c                 ó   — | S r�   r`   rN   s    r;   Ú	__enter__zSandbox.__enter__  ó   € Øˆr=   c                 óh   — | j         r|                      ¦   «          d S |                      ¦   «          d S r�   )r—  rt   rh  ©rO   Úexc_infos     r;   Ú__exit__zSandbox.__exit__  s/   € ØÔð 	Ø�IŠI‰KŒKˆKˆKˆKà�JŠJ‰LŒLˆLˆLˆLr=   .)
r  r   ÚcwdrZ  ÚstdinÚ	on_stdoutÚ	on_stderrÚcheckÚcapture_outputÚ
backgroundre   r  rÚ  rZ  rÛ  rÜ  rÝ  rÞ  rß  rà  c       
         ó   — d S r�   r`   )rO   re   r  r   rÚ  rZ  rÛ  rÜ  rÝ  rÞ  rß  rà  s               r;   ÚrunzSandbox.run  s	   € ð  #˜sr=   )r  r   rÚ  Tc                ó   — d S r�   r`   )rO   re   r  r   rÚ  rà  s         r;   râ  zSandbox.run(  s	   € ð ˜r=   c       
         óZ  ‡
‡— t          ||¦  «        }|r||d<   |r||d<   |rj|                      dd|¬¦  «                             ¦   «         }t          |                     d¦  «        |d         ||                     d¦  «        | ¬	¦  «        S |�||d<   |�||d<   g }g }dŠd
}dt
          t                   dt          dd
fˆ
ˆfd„}|                      dd|¬¦  «        5 }t          |¦  «        D ]ð}|d         dk    r& |||d         ¦  «         |� ||d         ¦  «         Œ4|d         dk    r& |||d         ¦  «         |� ||d         ¦  «         Œf|d         dk    r~t          |d         d 
                    |¦  «        d 
                    |¦  «        |                     d¦  «        |                     dd¦  «        |                     dd¦  «        ¬¦  «        } nŒñd
d
d
¦  «         n# 1 swxY w Y   |€t          d¦  «        ‚|	r#|j        dk    s|j        rt          ||¬¦  «        ‚|S ) 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.
            capture_output (`bool`, *optional*, defaults to `True`):
                If True, accumulate stdout/stderr into the returned result. Pass `False`
                when you only want `on_stdout`/`on_stderr`: output is then handed to the
                callbacks and dropped, so a command producing gigabytes does not have to fit
                in memory. `result.stdout`/`result.stderr` are empty in that case.
            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©rq   rc   rd   rj   )rc   rd   re   rj   ri   NrZ  rÛ  r   Úpartsr±   r3   c                 óÄ   •— ‰sd S ‰t          |¦  «        z   t          k    rt          dt          › d�¦  «        ‚‰t          |¦  «        z  Š|                      |¦  «         d S )Nzcommand produced more than z  characters of output. Pass `capture_output=False` with `on_stdout`/`on_stderr` to stream it instead, or redirect it to a file in the sandbox and download that.)rU   ÚMAX_CAPTURED_OUTPUT_CHARSr   Úappend)rç  r±   rß  Úcaptureds     €€r;   ÚkeepzSandbox.run.<locals>.keepŠ  s~   ø€ à!ð Ø�Ø�#˜d™)œ)Ñ#Õ&?Ò?Ð?Ý"ðQÕ2Kð Qð Qð Qñô ð ð
 �˜D™	œ	Ñ!ˆHØ�LŠL˜ÑÔÐÐÐr=   z/execr  rG   rH   ÚexitrF   r   rI   rJ   FrK   )rF   rG   rH   rI   rJ   rK   z%connection lost while running command)re   Úresult)r  rp   rq   rb   rr   rØ   r]   rÈ   r  rE   Újoinr   rF   rJ   r   )rO   re   r  r   rÚ  rZ  rÛ  rÜ  rÝ  rÞ  rß  rà  rü   r±   Ústdout_partsÚstderr_partsrî  rì  rs   r  rë  s             `         @r;   râ  zSandbox.run3  së  øø€ õt    UÑ+Ô+ˆØð 	!Ø ˆG�E‰NØð 	!Ø ˆG�E‰NØð 
	Ø—=’= ¨¸G�=ÑDÔD×IÒIÑKÔKˆDÝ!ð —8’8˜D‘>”>Ø˜”KØØ—H’H˜U‘O”OØðñ ô ð ð ÐØ!(ˆG�IÑØÐØ$ˆG�GÑð
 #%ˆØ"$ˆØˆØ.2ˆð	��Sœ	ð 	­ð 	°ð 	ð 	ð 	ð 	ð 	ð 	ð 	ð �\Š\˜& '°ˆ\Ñ8Ô8ð 	¸HÝ% hÑ/Ô/ð ð �Ø˜”> XÒ-Ð-Ø�D˜ u¨V¤}Ñ5Ô5Ð5Ø Ð,Ø!˜	 %¨¤-Ñ0Ô0Ð0øØ˜7”^ xÒ/Ð/Ø�D˜ u¨V¤}Ñ5Ô5Ð5Ø Ð,Ø!˜	 %¨¤-Ñ0Ô0Ð0øØ˜7”^ vÒ-Ð-Ý1Ø"'¨Ô"4Ø!Ÿwšw |Ñ4Ô4Ø!Ÿwšw |Ñ4Ô4Ø$Ÿyšy¨Ñ2Ô2Ø"'§)¢)¨K¸Ñ"?Ô"?Ø$)§I¢I¨m¸QÑ$?Ô$?ðñ ô �Fð �Eð .ð	ð 	ð 	ñ 	ô 	ð 	ð 	ð 	ð 	ð 	ð 	øøøð 	ð 	ð 	ð 	ð* ˆ>ÝÐFÑGÔGÐGØð 	>�fÔ&¨!Ò+Ð+¨vÔ/?Ð+Ý%¨#°fÐ=Ñ=Ô=Ð=Øˆs   ÃDG*Ç*G.Ç1G.c                 óp   ‡ — ‰                       dd¦  «                             ¦   «         }ˆ fd„|D ¦   «         S )a›  List the background processes of this sandbox.

        Returns the processes started with [`Sandbox.run`]`(..., background=True)`; stop one
        with [`SandboxProcess.kill`]. Recently completed processes stay listed (with
        `running=False` and their `exit_code`); the server keeps a bounded number of them, so a
        sandbox that has run thousands of short commands will not list them all.
        rÂ   rå  c                 óú   •— g | ]w}t          |                     d ¦  «        |d         |d         |                     d¦  «        |                     d¦  «        |d         |                     d¦  «        ‰¬¦  «        ‘ŒxS )rc   rd   re   rj   rk   rl   rF   )rc   rd   re   rj   rk   rl   rF   ri   )rb   rr   )rÏ   ÚprO   s     €r;   rÐ   z%Sandbox.processes.<locals>.<listcomp>»  sŠ   ø€ ð 
ð 
ð 
ð õ Ø—5’5˜‘;”;Ø�e”HØ�e”HØ—E’E˜%‘L”LØŸeše OÑ4Ô4Ø˜)œØŸ%š% Ñ,Ô,Øð	ñ 	ô 	ð
ð 
ð 
r=   )rp   rq   )rO   r±   s   ` r;   Ú	processeszSandbox.processes²  sQ   ø€ ð �}Š}˜U LÑ1Ô1×6Ò6Ñ8Ô8ˆð
ð 
ð 
ð 
ð ð
ñ 
ô 
ð 	
r=   c                 ó   — | j         j        S r�   )r”  r9  rN   s    r;   r9  zSandbox.imageË  s   € àŒ|Ô!Ð!r=   c                 ó,   — | j         �| j        j        ndS )zIFor a shared/pool sandbox, the job id of the host running it (else None).N)r•  r”  r  rN   s    r;   Úhost_idzSandbox.host_idÏ  s   € ð '+¤nÐ&@ˆtŒ|Ô"Ð"ÀdÐJr=   ú/zhttps://)ÚschemeÚportrx   rú  c                óª   — | j         j                             dd¦  «        d         }|                     d¦  «        r|nd|z   }|› |› | j        › d|› |› �S )a4  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://r   éÿÿÿÿrù  z/proxy/)r”  r:  rÊ  Ú
startswithr–  )rO   rû  rx   rú  Úhost_and_rests        r;   Úproxy_url_forzSandbox.proxy_url_forÖ  sg   € ðL œÔ-×3Ò3°E¸1Ñ=Ô=¸bÔAˆØ—’ sÑ+Ô+Ð;ˆtˆt°°t±ˆØÐM˜-ÐM¨¬ÐMÐMÀÐMÀtÐMÐMÐMr=   c                 óJ   — dt          | j        j        ¦  «        › �| j        dœS )a  Auth headers to send with [`proxy_url_for`] requests (HF token + sandbox token).

        Read these at the moment you use them: the HF token is resolved on access,
        so a long-lived handle hands out a current bearer rather than one captured
        when the sandbox was created.

        For a pooled sandbox this is the sandbox's own capability token, not the
        pool host's: these headers typically end up in a browser or WebSocket
        client, so they should confer access to this sandbox and nothing else.
        r)  )r*  r=  )r+  r”  r'  rC  rN   s    r;   Úproxy_headerszSandbox.proxy_headers   s3   € ð MÕ'7¸¼Ô8IÑ'JÔ'JÐLÐLØ#Ô2ð
ð 
ð 	
r=   c                 ó(   — d| j         ›d| j        ›d�S )NzSandbox(id=z, image=rT   )rc   r9  rN   s    r;   rW   zSandbox.__repr__  s   € Ø?˜TœWÐ?Ð?°´
Ð?Ð?Ð?Ð?r=   rX  Úresourcec                 óH   —  | j         j        || j        |z   fd| j        i|¤ŽS ©Nr;  )r”  r-  r–  rC  )rO   rX  r  rT  s       r;   rp   zSandbox._request  s2   € Ø#ˆtŒ|Ô# F¨D¬O¸hÑ,FÐtÐtÐVZÔViÐtÐmsÐtÐtÐtr=   c              +   óŠ   K  —  | j         j        || j        |z   fd| j        i|¤Ž5 }|V — d d d ¦  «         d S # 1 swxY w Y   d S r  )r”  rc  r–  rC  )rO   rX  r  rT  rs   s        r;   rÈ   zSandbox._stream  s¬   è è € à ˆTŒ\Ô Ø�D”O hÑ.ð
ð 
Ø>BÔ>Qð
ØU[ð
ð 
ð 	àØˆNˆNˆNð	ð 	ð 	ñ 	ô 	ð 	ð 	ð 	ð 	ð 	ð 	ð 	øøøð 	ð 	ð 	ð 	ð 	ð 	s   ¦8¸<¿<r~  )r3   rh   )rù  ),rX   rY   rZ   r[   r]   r4  r^   rŸ   r  ÚDEFAULT_IMAGEÚDEFAULT_IDLE_TIMEOUTrA   rB   r€  r	   r   r   r¾  r]  rƒ  rt   rŽ  rh  rÔ  rÙ  r   r   r   rE   râ  rb   rõ  r_   r9  rø  r   r  rW   rG  r�  rp   r   r   rÈ   r`   r=   r;   rh   rh     s¹  € € € € € ðð ð. %)ð (ð  (ð  (ð ð (ð ð	 (ð
 ˜‘*ð (ð ð (ð ð (ð ˜T‘zð (ð 
ð (ð  (ð  (ð  (ðH ð #ðrað "Ø1EØ%)Ø)-Ø'+Ø $Ø!&Ø(,Ø$Ø ðrað rað raàðrað ð	rað
 ˜E‘k CÑ'¨$Ñ.ðrað �#�s�(Œ^˜dÑ"ðrað �c˜3�h” $Ñ&ðrað �f” Ñ$ðrað ˜‘:ðrað ðrað �S˜#�X” Ñ%ðrað ðrað �T‰zðrað 
ðrað rað rañ „[ðraðh ØAEÐ[_ð .bð .bð .b ð .b°C¸$±Jð .bÈcÐTXÉjð .bÐdmð .bð .bð .bñ „[ð.bðd ˆ;‰=Œ=€Dð!ð !ð !ð !ð.!ð !ð !ð !ðð ð ð ðð ð ð ð ð
 !Ø%(ØØ #ØØ25Ø25ØØ"Ø%(ð#ð #ð #à�4˜”9‰_ð#ð �d‰{ð	#ð
 �#�s�(Œ^˜dÑ"ð#ð �4‰Zð#ð ˜‘ð#ð �T‰zð#ð ˜S˜E 4˜KÔ(¨4Ñ/ð#ð ˜S˜E 4˜KÔ(¨4Ñ/ð#ð ð#ð ð#ð ˜E”Nð#ð 
ð#ð #ð #ñ „Xð#ð  ð
 !Ø%(Øðð ð à�4˜”9‰_ðð �d‰{ð	ð
 �#�s�(Œ^˜dÑ"ðð �4‰Zðð ˜D”Mðð 
ðð ð ñ „Xðð "Ø%)ØØ $Ø Ø26Ø26ØØ#Ø ð}ð }ð }à�4˜”9‰_ð}ð �d‰{ð	}ð
 �#�s�(Œ^˜dÑ"ð}ð �4‰Zð}ð ˜‘ð}ð �T‰zð}ð ˜S˜E 4˜KÔ(¨4Ñ/ð}ð ˜S˜E 4˜KÔ(¨4Ñ/ð}ð ð}ð ð}ð ð}ð 
 Ñ	.ð}ð }ð }ð }ð~
˜4 Ô/ð 
ð 
ð 
ð 
ð2 ð"�s˜T‘zð "ð "ð "ñ „Xð"ð ðK˜˜t™ð Kð Kð Kñ „XðKð(NÈzð (Nð (Nð (N #¨¡)ð (N°3ð (NÈð (NÐ^að (Nð (Nð (Nð (NðT ð
˜t C¨ Hœ~ð 
ð 
ð 
ñ „Xð
ð @˜#ð @ð @ð @ð @ð
u˜sð u¨cð uÀÄð uð uð uð uð ð˜cð ¨Sð ¸xÈÌÔ?Xð ð ð ñ „^ðð ð r=   rh   c                   ó  — e Zd ZdZefdedddeddedddœded	ed
e	de	de	dz  dedz  de	e
z  ez  dz  dedz  de
dededz  deddfd„Zededdœdededz  dededz  dd f
d„¦   «         ZdFde	dee         fd„Zdeddœdeeef         dz  de	e
z  ez  dz  deddfd„Zdeeef         dz  de	e
z  ez  dz  deddfd „Zede	fd!„¦   «         Zede	fd"„¦   «         Zedee         fd#„¦   «         ZdGd$„ZdHd%„ZdGd&„ZdGd'„Zdedz  fd(„Zd)edefd*„Zd)edefd+„Z dId-„Z!d.ed/         dd,fd0„Z"defd1„Z#dGd2„Z$de	fd3„Z%dd4œd5e	d6edee&         fd7„Z'de&fd8„Z(d9d/deeef         d:e	dz  dd;fd<„Z)d=e*ddfd>„Z+d9e&ddfd?„Z,dGd@„Z-dAe.defdB„Z/dJdKdE„Z0dS )LÚSandboxPoolu�	  A fleet of shared "host" jobs, each packing many landlock-isolated sandboxes.

    > [!WARNING]
    > The Sandbox API is experimental. Its API and behavior may change without notice.
    >
    > **Pooled sandboxes are for workloads inside one trust boundary.** A pooled sandbox is a uid plus a Landlock
    > ruleset inside a shared VM â€” not a VM of its own â€” and every sandbox on a host shares that host's auth token
    > and its privileged control plane. Use a pool to fan out *your own* code cheaply. For mutually distrusting
    > workloads, use [`Sandbox.create`], which gives each one its own VM. The specific gaps are listed under
    > "Known limitations" in the sandbox conceptual guide.

    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   Nr�  F)rž  Úsandboxes_per_hostÚwarm_upÚ	max_hostsrw   rŸ  r)   rl  Úadopt_hostsr/  Ú_connect_moder9  rž  r  r  r  rw   rŸ  r)   rl  r  r/  r  r3   c                ó‚  — |
t           t          t          fvr+t          dt           ›dt          ›dt          ›d|
›d�	¦  «        ‚|dk     rt          d¦  «        ‚|dk     rt          d¦  «        ‚t	          |¬¦  «        | _        || _        || _        || _        || _	        || _
        |�|nd
t          d¦  «        › �| _        || _        || _        t          | j        |¦  «        | _        |	| _        |
| _        d	| _        d| _        g | _        t+          j        ¦   «         | _        t+          j        ¦   «         | _        t+          j        ¦   «         | _        d| _        d| _        || _        | | _        d| _        t+          j        | j        ¦  «        | _         tC          ¦   «         | _"        |s|  #                    ¦   «          d	S d	S )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. The cap is enforced
                per-process against the hosts this handle knows about, so two processes
                using the same pool concurrently can exceed it. (Per-host density,
                `sandboxes_per_host`, *is* enforced by the host itself.)
            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.
            adopt_hosts (`str`, *optional*, defaults to `"own"`):
                Which already-running hosts `create()` may pack onto. Hosts are found by
                filtering Jobs on labels, and labels are set by whoever creates the Job â€” so a
                label match is a claim, not proof. This decides how much more than the claim is
                required:

                - `"own"` (default): only Jobs this principal started, per the Jobs API's
                  `initiator`. Safe in a shared namespace.
                - `"namespace"`: any Job in the namespace carrying the pool's labels, provided
                  its image, flavor, command and exposed URL all match. Restores cross-user
                  host sharing; only use it in a namespace whose members you trust, since any
                  of them can publish a Job your client will then send a token to.
                - `"never"`: no adoption at all â€” this handle only uses hosts it booted itself.
            token (`str`, *optional*):
                HF token override.
        zadopt_hosts must be one of z, z; got r+   r   z sandboxes_per_host must be >= 1.zwarm_up must be >= 1.r1  Nzpool-é   Fr   )$Ú	ADOPT_OWNÚADOPT_NAMESPACEÚADOPT_NEVERr  r   r'  r9  rž  r  Ú_warm_upr  r   rw   Ú_idle_timeoutÚ
_namespaceÚ_cache_contextÚ_start_timeoutÚ_adopt_hostsÚ
_principalÚ_principal_resolvedÚ_hostsrñ   rò   Ú_lockÚ_warmup_lockÚ
_boot_lockÚ_closedÚ
_warmed_upÚ_require_live_hostÚ_owns_hostsÚ
_in_flightÚ	ConditionÚ_drainedÚsetÚ_dead_host_idsÚ_ensure_warmed_up)rO   r9  rž  r  r  r  rw   rŸ  r)   rl  r  r/  r  s                r;   rŸ   zSandboxPool.__init__N  sÓ  € ðN �y­/½;ÐGÐGÐGÝØw­iÐwÐw½_ÐwÐwÕR]ÐwÐwÐgrÐwÐwÐwñô ð ð  Ò!Ð!ÝÐ?Ñ@Ô@Ð@Ø�QŠ;ˆ;ÝÐ4Ñ5Ô5Ð5Ý Ð&Ñ&Ô&ˆŒ	ØˆŒ
ØˆŒØ"4ˆÔØˆŒØ"ˆŒØ Ð,�D�DÐ2H½)ÀA¹,¼,Ð2HÐ2HˆŒ	Ø)ˆÔØ#ˆŒõ -¨T¬Y¸	ÑBÔBˆÔØ+ˆÔØ'ˆÔð '+ˆŒØ#(ˆÔ Ø,.ˆŒÝ”^Ñ%Ô%ˆŒ
õ &œNÑ,Ô,ˆÔõ
 $œ.Ñ*Ô*ˆŒØˆŒàˆŒð #0ˆÔð  -Ð,ˆÔð ˆŒÝ!Ô+¨D¬JÑ7Ô7ˆŒå(+©¬ˆÔð
 ð 	%Ø×"Ò"Ñ$Ô$Ð$Ð$Ð$ð	%ð 	%r=   )r)   r  r/  Úpool_idc                ór  — t          |¬¦  «        }t          |t          ||¦  «        ¦  «        }|�. | |j        |j        |j        |j        ||j        |||d¬¦
  «
        S t          ||||¬¦  «        }t          |||¬¦  «        }| 
                    d¦  «        }	| 
                    d¦  «        }
 | |j        p|j        pt          |j        �t          |j        ¦  «        nd	t          | 
                    d
t           ¦  «        ¦  «        |
�t          |
¦  «        nd||	�t          |	¦  «        nd|||d¬¦
  «
        S )uh  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).
            adopt_hosts (`str`, *optional*, defaults to `"own"`):
                Which hosts may be attached to. See [`SandboxPool`]. Reattaching to a pool whose
                hosts another member of the namespace started needs `"namespace"`.
            token (`str`, *optional*):
                HF token override.
        r1  NT)
r9  rž  r  r  rw   rŸ  r)   r  r/  r  ©r)   Úpolicyrp  ÚSBX_IDLE_TIMEOUTÚSBX_MAX_HOSTSrœ  ÚSBX_CAPACITY)r   r   r  r9  rž  r  r  rŸ  Ú_find_pool_host_jobÚ	_host_envrr   rN  rO  r  r]   rA   ÚDEFAULT_SANDBOXES_PER_HOST)rQ  r,  r)   r  r/  r%  ÚcacherK  r   Úidle_rawÚmax_hosts_raws              r;   r]  zSandboxPool.connectÖ  sX  € õ< ˜%Ð Ñ Ô ˆõ   ­¸¸YÑ)GÔ)GÑHÔHˆØÐØ�3Ø”kØ”|Ø#(Ô#;Øœ/ØØ"Ô/Ø#Ø'ØØ"ðñ ô ð õ " # w¸)ÈKÐXÑXÔXˆÝ˜˜S¨IÐ6Ñ6Ô6ˆØ—7’7Ð-Ñ.Ô.ˆØŸš Ñ0Ô0ˆØˆsØÔ"ÐC c¤lÐCµmØ&)¤jÐ&<•3�s”z‘?”?�?À+Ý" 3§7¢7¨>Õ;UÑ#VÔ#VÑWÔWØ,9Ð,E•c˜-Ñ(Ô(Ð(È4ØØ*2Ð*>�˜X™œ˜ÀDØØ#ØØð
ñ 
ô 
ð 	
r=   Ú	num_hostsc                 óð  — | j         rt          d¦  «        ‚|                      ¦   «          | j        5  |t	          | j        ¦  «        z
  }ddd¦  «         n# 1 swxY w Y   |dk    rP|                      |d¬¦  «        }| j        5  | j                             |¦  «         ddd¦  «         n# 1 swxY w Y   | j        5  d| _	        ddd¦  «         n# 1 swxY w Y   |  
                    ¦   «          | j        S )u¢  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.Nr   T©Úallow_partial)r"  r   Ú_discover_hostsr  rU   r  Ú_provision_hostsrß   r   r#  Ú_save_cacheÚhost_ids)rO   r9  Ú	shortfallÚbooteds       r;   ÚwarmzSandboxPool.warm  s³  € ð Œ<ð 	>ÝÐ<Ñ=Ô=Ð=Ø×ÒÑÔÐØŒZð 	5ð 	5Ø!¥C¨¬Ñ$4Ô$4Ñ4ˆIð	5ð 	5ð 	5ñ 	5ô 	5ð 	5ð 	5ð 	5ð 	5ð 	5ð 	5øøøð 	5ð 	5ð 	5ð 	5à�qŠ=ˆ=Ø×*Ò*¨9ÀDÐ*ÑIÔIˆFØ”ð +ð +Ø”×"Ò" 6Ñ*Ô*Ð*ð+ð +ð +ñ +ô +ð +ð +ð +ð +ð +ð +øøøð +ð +ð +ð +àÔð 	#ð 	#Ø"ˆDŒOð	#ð 	#ð 	#ñ 	#ô 	#ð 	#ð 	#ð 	#ð 	#ð 	#ð 	#øøøð 	#ð 	#ð 	#ð 	#à×ÒÑÔÐØŒ}Ðs5   ²AÁAÁAÂB,Â,B0Â3B0Â>CÃCÃC)r   rŸ  r£  r   r£  rh   c                óæ  — | j         5  | j        rt          d¦  «        ‚| xj        dz  c_        ddd¦  «         n# 1 swxY w Y   	 |                      |||¦  «        | j         5  | xj        dz  c_        | j                             ¦   «          ddd¦  «         S # 1 swxY w Y   S # | j         5  | xj        dz  c_        | j                             ¦   «          ddd¦  «         w # 1 swxY w Y   w xY w)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.
        r;  r   N)r  r"  r   r&  Ú_create_lockedr(  Ú
notify_all)rO   r   rŸ  r£  s       r;   r¾  zSandboxPool.create7  s·  € ð: ŒZð 	!ð 	!ØŒ|ð BÝ"Ð#@ÑAÔAÐAð ˆOŒO˜qÑ ˆOŒOð	!ð 	!ð 	!ñ 	!ô 	!ð 	!ð 	!ð 	!ð 	!ð 	!ð 	!øøøð 	!ð 	!ð 	!ð 	!ð	+Ø×&Ò& s¨LÐ:JÑKÔKà”ð +ð +Ø�” 1Ñ$�”Ø”×(Ò(Ñ*Ô*Ð*ð+ð +ð +ñ +ô +ð +ð +ð +ð +ð +ð +øøøð +ð +ð +ð +ð +ø�”ð +ð +Ø�” 1Ñ$�”Ø”×(Ò(Ñ*Ô*Ð*ð+ð +ð +ñ +ô +ð +ð +ð +ð +ð +ð +øøøð +ð +ð +ð +ð +øøøsO   ˆ';»?Á?ÁB& Á$*BÂB	Â!B	Â&C0Â.*C$ÃC0Ã$C(Ã(C0Ã+C(Ã,C0c                 óœ  ‡
— t          |pi ¦  «        }|rt          | j        ¦  «        |d<   |�t          |¦  «        nd }g Š
d}d}	 |                      ¦   «          	 |                      ¦   «         }|€,|s*d}|                      ¦   «          |                      ¦   «         }|€W| j        r;|r9| j        s2t          | j
        | j        ¦  «         t          d| j
        › d�¦  «        ‚|                      ‰
¦  «        }|�•	 |                      |||¦  «        }	nK# t          $ r> | j        5  t#          d|j        dz
  ¦  «        |_        d d d ¦  «         n# 1 swxY w Y   ‚ w xY w|	�|                      ¦   «          |	S |‰
v r‰
                     |¦  «         d}|dz  }|t*          k    rt          d¦  «        ‚�ŒU# t          $ r‘ | j        5  ˆ
fd	„| j        D ¦   «         | _        d d d ¦  «         n# 1 swxY w Y   ‰
D ]U}	 |                     ¦   «          n# t          $ r Y nw xY w|                     ¦   «          Œ=# |                     ¦   «          w xY w‚ w xY w)
NÚHF_TOKENFr   Tú No running host found for pool 'úX'. The pool has stopped (all its hosts were killed or idle-timed-out); create a new one.r   zZCould not place sandbox: hosts kept reporting full. Raise max_hosts or sandboxes_per_host.c                 ó   •— g | ]}|‰v¯|‘Œ	S r`   r`   )rÏ   ÚhÚ	new_hostss     €r;   rÐ   z.SandboxPool._create_locked.<locals>.<listcomp>¥  s#   ø€ ÐLÐLÐL Q¸À)Ð9KÐ9K˜qÐ9KÐ9KÐ9Kr=   )r€  r+  r'  rC   r+  Ú_reserve_oner>  r$  r  r   rw   r  r   Ú_boot_one_hostÚ_create_oner  r  ÚmaxrD  r@  ÚremoveÚ_MAX_PACK_ROUNDSrk  rh  )rO   r   rŸ  r£  Úsandbox_envÚ	idle_secsÚ
discoveredÚroundsÚhostr›   rN  s             @r;   rF  zSandboxPool._create_lockeda  s{  ø€ õ ˜3˜9 "‘o”oˆØð 	BÝ&6°t´yÑ&AÔ&AˆK˜
Ñ#ð 8DÐ7OÕ% lÑ3Ô3Ð3ÐUYˆ	à*,ˆ	Øˆ
Øˆð<	ð ×"Ò"Ñ$Ô$Ð$ð,à×(Ò(Ñ*Ô*�à�<¨
�<Ø!%�JØ×(Ò(Ñ*Ô*Ð*Ø×,Ò,Ñ.Ô.�Dà�<ØÔ.ð °:ð ÀdÄkð õ *¨$¬)°TÔ5HÑIÔIÐIÝ*ð_¸t¼yð _ð _ð _ñô ð ð  ×.Ò.¨yÑ9Ô9�Dð Ð#ðØ"&×"2Ò"2°4¸ÀiÑ"PÔ"P˜˜øÝ$ð ð ð ð "œZð >ð >Ý(+¨A¨t¬y¸1©}Ñ(=Ô(=˜DœIð>ð >ð >ñ >ô >ð >ð >ð >ð >ð >ð >øøøð >ð >ð >ð >àðøøøð Ð*Ø×(Ò(Ñ*Ô*Ð*Ø&˜ð
 ˜yÐ(Ð(Ø!×(Ò(¨Ñ.Ô.Ð.Ø"�
Ø˜!‘�ØÕ,Ò,Ð,Ý&Øtñô ð ñU,øõZ ð 	ð 	ð 	à”ð Mð MØLÐLÐLÐL¨$¬+ÐLÑLÔL�”ðMð Mð Mñ Mô Mð Mð Mð Mð Mð Mð Møøøð Mð Mð Mð Mà!ð !ð !�ð!Ø—O’OÑ%Ô%Ð%Ð%øÝ ð ð ð Ø�Dðøøøð —J’J‘L”L�L�Lø�D—J’J‘L”L�L�LøøøØð	øøøs©   ÁB2F0 Ã9D ÄF0 ÄEÄ"EÅ EÅE	ÅEÅE	ÅEÅF0 Å4<F0 Æ0IÇG&ÇIÇ&G*	Ç*IÇ-G*	Ç.IÇ6HÈ
H0È
HÈH0ÈHÈH0ÈIÈ0IÉIc                 ól   — | j         5  t          | j        ¦  «        cddd¦  «         S # 1 swxY w Y   dS )z*Number of host jobs currently provisioned.N)r  rU   r  rN   s    r;   r9  zSandboxPool.num_hosts¯  s}   € ð ŒZð 	$ð 	$Ý�t”{Ñ#Ô#ð	$ð 	$ð 	$ð 	$ñ 	$ô 	$ð 	$ð 	$ð 	$ð 	$ð 	$ð 	$øøøð 	$ð 	$ð 	$ð 	$ð 	$ð 	$s   ˆ)©-°-c                 ó€   — | j         5  t          d„ | j        D ¦   «         ¦  «        cddd¦  «         S # 1 swxY w Y   dS )z<Number of sandboxes currently handed out (across all hosts).c              3   ó$   K  — | ]}|j         V — Œd S r�   )rD  ©rÏ   rY  s     r;   rù   z,SandboxPool.num_sandboxes.<locals>.<genexpr>¹  s$   è è € Ð9Ð9 T�t”yÐ9Ð9Ð9Ð9Ð9Ð9r=   N)r  Úsumr  rN   s    r;   Únum_sandboxeszSandboxPool.num_sandboxesµ  sŒ   € ð ŒZð 	:ð 	:ÝÐ9Ð9¨T¬[Ð9Ñ9Ô9Ñ9Ô9ð	:ð 	:ð 	:ð 	:ñ 	:ô 	:ð 	:ð 	:ð 	:ð 	:ð 	:ð 	:øøøð 	:ð 	:ð 	:ð 	:ð 	:ð 	:s   ˆ3³7º7c                 óf   — | j         5  d„ | j        D ¦   «         cddd¦  «         S # 1 swxY w Y   dS )z!Job ids of the provisioned hosts.c                 ó   — g | ]	}|j         ‘Œ
S r`   ©r  r]  s     r;   rÐ   z(SandboxPool.host_ids.<locals>.<listcomp>¿  s   € Ð8Ð8Ð8 D�D”KÐ8Ð8Ð8r=   N)r  r  rN   s    r;   rA  zSandboxPool.host_ids»  sƒ   € ð ŒZð 	9ð 	9Ø8Ð8¨D¬KÐ8Ñ8Ô8ð	9ð 	9ð 	9ð 	9ñ 	9ô 	9ð 	9ð 	9ð 	9ð 	9ð 	9ð 	9øøøð 	9ð 	9ð 	9ð 	9ð 	9ð 	9s   ˆ&¦*­*c           
      ó¼  ‡ — ‰ j         5  ‰ j        r	 ddd¦  «         dS d‰ _        ‰ j        t          z   }‰ j        rM‰ j                             ˆ fd„|¬¦  «        s.t                               d‰ j	        › d‰ j        › d|› d�¦  «         ‰ j
        }g ‰ _
        ddd¦  «         n# 1 swxY w Y   g }g }|D ]½}	 |j        r|                     ¦   «          nq# t          $ rd}|                     |¦  «         |                     |j        › d	|› d
�¦  «         t                               d|j        › d|› �¦  «         Y d}~nd}~ww xY w|                     ¦   «          Œ¥# |                     ¦   «          w xY w|r‰                      |¬¦  «         n!‰ j        rt'          ‰ j	        ‰ j        ¦  «         |r.t+          d‰ j	        › dd                     |¦  «        › d�¦  «        ‚dS )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>`.

        Only hosts *this handle started* are cancelled. A host discovered via labels may
        be serving another process' sandboxes, so it is released rather than terminated.

        Raises [`SandboxError`] if a host job could not be cancelled, naming the jobs that
        are still running â€” they keep billing, and their cache entries are kept so they stay
        discoverable. When `close()` is reached through `__exit__` with an exception already
        in flight, the failure is logged instead, so it cannot mask the original error.
        NTc                  ó   •— ‰ j         dk    S rM   )r&  rN   s   €r;   ú<lambda>z#SandboxPool.close.<locals>.<lambda>Û  s   ø€ ÀdÄoÐYZÒFZ€ r=   rn  úPool 'ú': z$ operation(s) still in flight after z(s; any host they boot will keep running.ú (rT   úFailed to cancel sandbox host rÐ  )Úhostsz#' could not terminate host job(s): ú; zM. They are still running and billing; cancel them with `hf jobs cancel <id>`.)r  r"  r  Ú_CLOSE_DRAIN_TIMEOUTr&  r(  Úwait_forr·  r¸  rw   r  rF  rk  r  rê  r  rh  r@  r%  r   r  r   rï  )rO   Údrain_timeoutrj  Ú	survivorsÚfailuresrY  r  s   `      r;   rh  zSandboxPool.closeÁ  sÑ  ø€ ð" ŒZð 	ð 	ØŒ|ð Øð	ð 	ð 	ñ 	ô 	ð 	ð 	ð 	ð  ˆDŒLð
 !Ô/Õ2FÑFˆMØŒð  t¤}×'=Ò'=Ð>ZÐ>ZÐ>ZÐ>ZÐdqÐ'=Ñ'rÔ'rð Ý—’ðO˜TœYð Oð O¨4¬?ð Oð OØ$ðOð Oð Oñô ð ð ”KˆEØˆDŒKð	ð 	ð 	ñ 	ô 	ð 	ð 	ð 	ð 	ð 	ð 	øøøð 	ð 	ð 	ð 	ð" +-ˆ	Ø ˆØð 	ð 	ˆDðð ”:ð &Ø—O’OÑ%Ô%Ð%øøÝð Tð Tð Tð × Ò  Ñ&Ô&Ð&Ø—’ 4¤;Ð 6Ð 6°!Ð 6Ð 6Ð 6Ñ7Ô7Ð7Ý—’ÐRÀÄÐRÐRÈqÐRÐRÑSÔSÐSÐSÐSÐSÐSÐSøøøøðTøøøð —
’
‘”��ø�—
’
‘”��øøøàð 	>à×Ò 9ÐÑ-Ô-Ð-Ð-ØÔð 	>å˜dœi¨Ô)<Ñ=Ô=Ð=Øð 	Ýð^˜œð ^ð ^ÀtÇyÂyÐQYÑGZÔGZð ^ð ^ð ^ñô ð ð	ð 	sH   ‰	B#ŸA8B#Â#B'Â*B'Â7CÃEÃ
EÃAD<Ä7EÄ<EÅEÅE/c                 ó   — | S r�   r`   rN   s    r;   rÔ  zSandboxPool.__enter__   rÕ  r=   c                 ó®   — 	 |                       ¦   «          d S # t          $ r2 |d         €‚ t                               d| j        › d�d¬¦  «         Y d S w xY w)Nr   rf  z/' teardown failed while handling another error.T)rØ  )rh  r   r·  r¸  rw   r×  s     r;   rÙ  zSandboxPool.__exit__  su   € ð	oØ�JŠJ‰LŒLˆLˆLˆLøÝð 	oð 	oð 	oð ˜Œ{Ð"ØÝ�NŠNÐ^ D¤IÐ^Ð^Ð^ÐimˆNÑnÔnÐnÐnÐnÐnð	oøøøs   ‚ ˜8AÁAc                 óô  — | j         5  | j        r	 ddd¦  «         dS |                      ¦   «          | j        €| j        nt          | j        | j        ¦  «        }| j        5  |t          | j        ¦  «        z
  }ddd¦  «         n# 1 swxY w Y   |dk    r§|  	                    ¦   «          | j
        sŒ| j        5  |t          | j        ¦  «        z
  }ddd¦  «         n# 1 swxY w Y   |dk    rP|                      |d¬¦  «        }| j        5  | j                             |¦  «         ddd¦  «         n# 1 swxY w Y   d| _        ddd¦  «         n# 1 swxY w Y   | j        r|                      ¦   «          dS dS )u©  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.
        Nr   Tr<  )r   r#  Ú_seed_hosts_from_cacher  r  rÎ   r  rU   r  r>  r$  r?  rß   r@  )rO   ÚtargetrB  rC  s       r;   r+  zSandboxPool._ensure_warmed_up  s¡  € ð  Ôð 	#ð 	#ØŒð Øð	#ð 	#ð 	#ñ 	#ô 	#ð 	#ð 	#ð 	#ð ×'Ò'Ñ)Ô)Ð)Ø&*¤nÐ&<�T”]�]Å#ÀdÄmÐUYÔUcÑBdÔBdˆFØ”ð 6ð 6Ø"¥S¨¬Ñ%5Ô%5Ñ5�	ð6ð 6ð 6ñ 6ô 6ð 6ð 6ð 6ð 6ð 6ð 6øøøð 6ð 6ð 6ð 6à˜1Š}ˆ}Ø×$Ò$Ñ&Ô&Ð&ð Ô.ð 7Øœð >ð >Ø$*­S°´Ñ-=Ô-=Ñ$=˜	ð>ð >ð >ñ >ô >ð >ð >ð >ð >ð >ð >øøøð >ð >ð >ð >à  1’}�}Ø!%×!6Ò!6°yÐPTÐ!6Ñ!UÔ!U˜Ø!œZð 7ð 7Ø œK×.Ò.¨vÑ6Ô6Ð6ð7ð 7ð 7ñ 7ô 7ð 7ð 7ð 7ð 7ð 7ð 7øøøð 7ð 7ð 7ð 7à"ˆDŒOð'	#ð 	#ð 	#ñ 	#ô 	#ð 	#ð 	#ð 	#ð 	#ð 	#ð 	#øøøð 	#ð 	#ð 	#ð 	#ð, Œ;ð 	Ø×ÒÑÔÐÐÐð	ð 	sƒ   ˆ	EžAEÁ!BÁ9EÂB		Â	EÂB		Â+EÂ8CÃEÃC 	Ã EÃ#C 	Ã$'EÄD2Ä&EÄ2D6	Ä6EÄ9D6	Ä:
EÅEÅEc                 ó  — | j         sw	 | j                             d¬¦  «                             d¦  «        | _        | j        du| _         n4# t
          $ r'}t                               d|› �¦  «         Y d}~nd}~ww xY w| j        S )zGId of the principal this pool authenticates as, for the `"own"` policy.T©r6  rc   Nú;Could not resolve the current user to validate pool hosts: )r  r'  Úwhoamirr   r  r  r·  r¸  rÑ  s     r;   Ú_principal_idzSandboxPool._principal_id8  s¦   € àÔ'ð 	bðbØ"&¤)×"2Ò"2¸Ð"2Ñ">Ô">×"BÒ"BÀ4Ñ"HÔ"H�”Ø+/¬?À$Ð+F�Ô(Ð(øÝð bð bð bå—’Ð`Ð]^Ð`Ð`ÑaÔaÐaÐaÐaÐaÐaÐaøøøøðbøøøð ŒÐs   ‰AA Á
A<ÁA7Á7A<rK  c           	      ó  — t          || j        | j        t          k    r|                      ¦   «         nd| j        | j        | j        ¬¦  «        }|�0t                               d|j	        › d| j
        › d|› d�¦  «         dS dS )	z9Whether `job` may be adopted as one of this pool's hosts.N©r/  Úprincipal_idr)   r9  rž  zNot adopting job ú as a host for pool 'rg  r+   FT©Ú_host_rejectionr  r  rz  r  r9  rž  r·  Údebugrc   rw   ©rO   rK  Úreasons      r;   Ú
_adoptablezSandboxPool._adoptableC  s•   € å ØØÔ$Ø15Ô1BÅiÒ1OÐ1O˜×+Ò+Ñ-Ô-Ð-ÐUYØ”oØ”*Ø”;ð
ñ 
ô 
ˆð ÐÝ�LŠLÐa¨S¬VÐaÐaÈ$Ì)ÐaÐaÐX^ÐaÐaÐaÑbÔbÐbØ�5Øˆtr=   c           	      ó  — t          || j        | j        t          k    r|                      ¦   «         nd| j        | j        | j        d¬¦  «        }|�0t                               d|j	        › d| j
        › d|› d�¦  «         dS dS )	zFLike `_adoptable`, minus the checks a not-yet-running job cannot pass.NF)r/  r}  r)   r9  rž  Ú	check_urlzNot waiting for job r~  rg  r+   Tr  r‚  s      r;   Ú_adoptable_pendingzSandboxPool._adoptable_pendingR  s˜   € å ØØÔ$Ø15Ô1BÅiÒ1OÐ1O˜×+Ò+Ñ-Ô-Ð-ÐUYØ”oØ”*Ø”;Øð
ñ 
ô 
ˆð ÐÝ�LŠLÐd°´ÐdÐdÈTÌYÐdÐdÐ[aÐdÐdÐdÑeÔeÐeØ�5Øˆtr=   ú_SandboxServer | Nonec                 óÀ   — | j         5  | j        D ]5}|j        |j        z
  dk    r |xj        dz  c_        |c cddd¦  «         S Œ6	 ddd¦  «         n# 1 swxY w Y   dS )zNReserve one slot on the first host with free capacity (under lock), else None.r   r   N)r  r  r7  rD  ©rO   rY  s     r;   rO  zSandboxPool._reserve_oneb  sÑ   € àŒZð 	 ð 	 Øœð  ð  �Ø”= 4¤9Ñ,¨qÒ0Ð0Ø�I”I ‘N�I”IØ�K�Kð		 ð 	 ð 	 ð 	 ñ 	 ô 	 ð 	 ð 	 à0ð ð	 ð 	 ð 	 ñ 	 ô 	 ð 	 ð 	 ð 	 ð 	 ð 	 ð 	 øøøð 	 ð 	 ð 	 ð 	 ð
 ˆts   ˆ0AÁAÁAÁArN  r4  c                 óê  — | j         5  |                      ¦   «         }|�|cddd¦  «         S |                      ¦   «         r$|                      ¦   «         }|�|cddd¦  «         S |                      d¦  «        }|                     |¦  «         | j        5  | j                             |¦  «         ddd¦  «         n# 1 swxY w Y   |                      ¦   «         cddd¦  «         S # 1 swxY w Y   dS )uh  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.
        Nr   )r!  rO  Ú_adopt_pending_hostr?  rß   r  r  )rO   rN  rY  rC  s       r;   rP  zSandboxPool._boot_one_hostk  s·  € ð Œ_ð 	'ð 	'ð ×$Ò$Ñ&Ô&ˆDØÐØð	'ð 	'ð 	'ð 	'ñ 	'ô 	'ð 	'ð 	'ð ×'Ò'Ñ)Ô)ð  Ø×(Ò(Ñ*Ô*�ØÐ#Øð	'ð 	'ð 	'ð 	'ñ 	'ô 	'ð 	'ð 	'ð ×*Ò*¨1Ñ-Ô-ˆFØ×Ò˜VÑ$Ô$Ð$Ø”ð +ð +Ø”×"Ò" 6Ñ*Ô*Ð*ð+ð +ð +ñ +ô +ð +ð +ð +ð +ð +ð +øøøð +ð +ð +ð +à×$Ò$Ñ&Ô&ð!	'ð 	'ð 	'ð 	'ñ 	'ô 	'ð 	'ð 	'ð 	'ð 	'ð 	'ð 	'øøøð 	'ð 	'ð 	'ð 	'ð 	'ð 	's@   ˆC(­+C(Á%1C(ÂB=Â1C(Â=C	ÃC(ÃC	ÃC(Ã(C,Ã/C,c           
      óÔ  ‡ ‡‡— d„ ‰ j         D ¦   «         Št          ˆˆ fd„‰ j                             dt          t
          t          ‰ j        i‰ j        ¬¦  «        D ¦   «         d¦  «        Š‰€dS t           
                    d‰ j        › d‰j        › d	�¦  «         t          j        ¦   «         ‰ j        z   }t          j        ¦   «         |k     r�‰ j                             ‰j        ‰ j        ¬
¦  «        j        j        }|dvrdS |dk    r6‰                      ¦   «          t%          ˆfd„‰ j         D ¦   «         ¦  «        rdS t          j        d¦  «         t          j        ¦   «         |k     °�dS )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                 ó   — h | ]	}|j         ’Œ
S r`   rb  r]  s     r;   rÂ  z2SandboxPool._adopt_pending_host.<locals>.<setcomp>�  ó   € Ð5Ð5Ð5 �”Ð5Ð5Ð5r=   c              3   óX   •K  — | ]$}|j         ‰v¯‰                     |¦  «        ¯ |V — Œ%d S r�   )rc   r‡  ©rÏ   rK  ÚknownrO   s     €€r;   rù   z2SandboxPool._adopt_pending_host.<locals>.<genexpr>‘  sS   øè è € ð ð àð ”6 Ð&Ð&¨4×+BÒ+BÀ3Ñ+GÔ+GÐ&ð ð 'Ð&Ð&Ð&ðð r=   Ú
SCHEDULING©ru  r¤  r)   NFrf  z' host z: is already SCHEDULING; waiting for it instead of booting.rj  )r“  rÆ  rÆ  c              3   ó8   •K  — | ]}|j         ‰j        k    V — Œd S r�   ©r  rc   )rÏ   rY  Úpendings     €r;   rù   z2SandboxPool._adopt_pending_host.<locals>.<genexpr>«  s,   øè è € ÐIÐI°T�t”{ g¤jÒ0ÐIÐIÐIÐIÐIÐIr=   Tg      ð?)r  rû   r'  Ú	list_jobsr³  rÌ  Ú
POOL_LABELrw   r  r·  r�  rc   rr  r  rt  ru  rv  r>  Úanyry  )rO   rz  rv  r’  r—  s   `  @@r;   rŒ  zSandboxPool._adopt_pending_host‡  s‰  øøø€ ð 6Ð5¨¬Ð5Ñ5Ô5ˆÝðð ð ð ð àœ9×.Ò.Ø'Ý&­	µ:¸t¼yÐIØ"œoð /ñ ô ðñ ô ð ñ
ô 
ˆð ˆ?Ø�5Ý�ŠÐv˜dœiÐvÐv°´
ÐvÐvÐvÑwÔwÐwÝ”9‘;”; Ô!4Ñ4ˆÝŒi‰kŒk˜HÒ$Ð$Ø”I×)Ò)°´ÀtÄÐ)ÑWÔWÔ^ÔdˆEØÐ5Ð5Ð5Ø�uØ˜	Ò!Ð!ð ×$Ò$Ñ&Ô&Ð&ÝÐIÐIÐIÐI¸T¼[ÐIÑIÔIÑIÔIð  Ø˜4ÝŒJ�s‰OŒOˆOõ Œi‰kŒk˜HÒ$Ð$ð ˆur=   c                 óÀ  ‡ ‡‡— d„ ‰ j         D ¦   «         Šˆˆ fd„‰ j                             dt          t          t
          ‰ j        i‰ j        ¬¦  «        D ¦   «         }|D �]~Šd}	 t          ‰ j        ‰j	        ‰ j        ¬¦  «        }t          ‰ j        ‰‰ j        ¬¦  «        }t          |                     d‰ j        ¦  «        ¦  «        |_        t          |                     dd	¦  «                             ¦   «         ¦  «        |_        ne# t&          t(          j        t,          f$ rF}t.                               d
‰j	        › d|› �¦  «         |�|                     ¦   «          Y d}~�Œd}~ww xY w‰ j        5  t7          ˆfd„‰ j         D ¦   «         ¦  «        r|                     ¦   «          n‰ j                              |¦  «         ddd¦  «         n# 1 swxY w Y   �Œ€dS )a<  Attach to running host jobs carrying this pool's labels.

        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.

        Labels select candidates; creator, job specification and proxy URL admission
        checks decide which candidates can receive credentials. Adopted hosts are released
        by close(), not cancelled, because another handle may still be using them.
        c                 ó   — h | ]	}|j         ’Œ
S r`   rb  r]  s     r;   rÂ  z.SandboxPool._discover_hosts.<locals>.<setcomp>»  r�  r=   c                 óP   •— g | ]"}|j         ‰v¯‰                     |¦  «        ¯ |‘Œ#S r`   )rc   r„  r‘  s     €€r;   rÐ   z/SandboxPool._discover_hosts.<locals>.<listcomp>¼  sE   ø€ ð 
ð 
ð 
àð
 Œv˜UÐ"Ð" t§¢°sÑ';Ô';Ð"ð ð #Ð"Ð"r=   rÆ  r”  Nrp  r2  rÂ   rÃ  zSkipping host z during discovery: c              3   ó8   •K  — | ]}|j         ‰j        k    V — Œd S r�   r–  )rÏ   rY  rK  s     €r;   rù   z.SandboxPool._discover_hosts.<locals>.<genexpr>×  s,   øè è € ÐEÐE°�t”{ c¤fÒ,ÐEÐEÐEÐEÐEÐEr=   )r  r'  r˜  r³  rÌ  r™  rw   r  rË  rc   r4  rA   rr   r  r7  rU   r-  rq   rD  r   rG  Ú	HTTPErrorr   r·  r�  rh  r  rš  rê  )rO   Úmatchesr�  r   r  rK  r’  s   `    @@r;   r>  zSandboxPool._discover_hosts°  s4  øøø€ ð 6Ð5¨¬Ð5Ñ5Ô5ˆð
ð 
ð 
ð 
ð 
à”y×*Ò*Ø Ý"¥I­z¸4¼9ÐEØœ/ð +ñ ô ð
ñ 
ô 
ˆð ð 	/ñ 	/ˆCØˆFðÝ& t¤y°#´&ÀDÄOÐTÑTÔT�õ   ¤	¨3¸$¼/ÐJÑJÔJ�Ý"% c§g¢g¨n¸dÔ>UÑ&VÔ&VÑ"WÔ"W�”Ý! &§.¢.°¸Ñ"HÔ"H×"MÒ"MÑ"OÔ"OÑPÔP�”�øÝ ¥&Ô"2µNÐCð ð ð õ —’ÐL¨c¬fÐLÐLÈÐLÐLÑMÔMÐMØÐ%Ø—L’L‘N”N�NØ���‘øøøøðøøøð ”ð /ð /ÝÐEÐEÐEÐE¸¼ÐEÑEÔEÑEÔEð /Ø—L’L‘N”N�N�Nà”K×&Ò& vÑ.Ô.Ð.ð	/ð /ð /ñ /ô /ð /ð /ð /ð /ð /ð /øøøð /ð /ð /ð /ùð!	/ð 	/s,   Á$B$D	Ä	E+Ä%;E&Å&E+Å5AGÇG	ÇG	c                 óª  — | j         5  d„ | j        D ¦   «         }ddd¦  «         n# 1 swxY w Y   	 | j                             dt          t
          t          | j        i| j        ¬¦  «        D ]}| 	                    |j
        ¦  «         Œn<# t          $ r/}t                               d| j        › d|› �¦  «         Y d}~nd}~ww xY wt          |¦  «        S )a¸  How many hosts are running for this pool, not just the ones we track.

        `max_hosts` is documented as a cost ceiling, but it was compared against
        `len(self._hosts)` -- an in-process count. Two processes using the same
        pool each counted only their own hosts, so the number of billed host jobs
        could quietly exceed the cap by a factor of however many processes were
        involved.

        Counting via labels narrows that considerably. It does not close it: two
        processes can still list simultaneously and both decide there is room. A
        hard cap has to be enforced where the jobs are created, not by the
        clients racing to count them.
        c                 ó   — h | ]	}|j         ’Œ
S r`   rb  r]  s     r;   rÂ  z/SandboxPool._live_host_count.<locals>.<setcomp>ë  s   € Ð;Ð;Ð; t�t”{Ð;Ð;Ð;r=   NrÆ  r”  z%Could not count live hosts for pool 'rg  )r  r  r'  r˜  r³  rÌ  r™  rw   r  Úaddrc   r  r·  r�  rU   )rO   ÚtrackedrK  r  s       r;   Ú_live_host_countzSandboxPool._live_host_countÜ  s=  € ð ŒZð 	<ð 	<Ø;Ð;¨t¬{Ð;Ñ;Ô;ˆGð	<ð 	<ð 	<ñ 	<ô 	<ð 	<ð 	<ð 	<ð 	<ð 	<ð 	<øøøð 	<ð 	<ð 	<ð 	<ð		TØ”y×*Ò*Ø Ý"¥I­z¸4¼9ÐEØœ/ð +ñ ô ð $ð $�ð
 —’˜CœFÑ#Ô#Ð#Ð#ð$øõ ð 	Tð 	Tð 	Tå�LŠLÐRÀÄÐRÐRÈqÐRÐRÑSÔSÐSÐSÐSÐSÐSÐSøøøøð	Tøøøõ �7‰|Œ|Ðs$   ˆ&¦*­*²AB
 Â

CÂ%B>Â>Cr<  Únum_newr=  c                ó  ‡ ‡— ‰ j         �ƒ‰                      ¦   «         }|r&t          |t          d‰ j         |z
  ¦  «        ¦  «        }||z   ‰ j         k    r9‰ j         |z
  }t	          d|› d‰ j         › dt          d|¦  «        › d|› d�	¦  «        ‚|dk    rg S t          t          |d¦  «        ¬	¦  «        5 Šˆˆ fd
„t          |¦  «        D ¦   «         }ddd¦  «         n# 1 swxY w Y   g }d}|D ]C}	 |                     |                     ¦   «         ¦  «         Œ+# t          $ r}	|	}Y d}	~	Œ<d}	~	ww xY w|�Z|D ]U}
	 |
 
                    ¦   «          n# t          $ r Y nw xY w|
                     ¦   «          Œ=# |
                     ¦   «          w xY w|‚|S )z=Boot `num_new` host jobs in parallel, respecting `max_hosts`.Nr   zPool needs z more host(s) but max_hosts=z allows only z more (zH already running for this pool). Raise max_hosts or kill some sandboxes.é    )Úmax_workersc                 óD   •— g | ]}‰                      ‰j        ¦  «        ‘ŒS r`   )ÚsubmitÚ
_boot_host)rÏ   Ú_rÛ   rO   s     €€r;   rÐ   z0SandboxPool._provision_hosts.<locals>.<listcomp>  s'   ø€ ÐPÐPÐP¸A�x—’ t¤Ñ7Ô7ÐPÐPÐPr=   )r  r¥  rÎ   rR  r   r   rÒ   rê  rî  r  rk  rh  )rO   r¦  r=  ÚcurrentÚallowedÚfuturesrC  r  Úfuturer  r�  rÛ   s   `          @r;   r?  zSandboxPool._provision_hostsø  sR  øø€ àŒ>Ð%Ø×+Ò+Ñ-Ô-ˆGØð IÝ˜g¥s¨1¨d¬n¸wÑ.FÑ'GÔ'GÑHÔH�Ø˜Ñ  4¤>Ò1Ð1Øœ.¨7Ñ2�Ý"ð> 'ð >ð >ÀtÄ~ð >ð >Ý#& q¨'¡?¤?ð>ð >Ø;Bð>ð >ð >ñô ð ð
 �aŠ<ˆ<ØˆIõ  ­C°¸Ñ,<Ô,<Ð=Ñ=Ô=ð 	QÀØPÐPÐPÐPÐPÅÀwÁÄÐPÑPÔPˆGð	Qð 	Qð 	Qñ 	Qô 	Qð 	Qð 	Qð 	Qð 	Qð 	Qð 	Qøøøð 	Qð 	Qð 	Qð 	Qà')ˆØ"&ˆØð 	ð 	ˆFðØ—’˜fŸmšm™oœoÑ.Ô.Ð.Ð.øÝð ð ð Ø������øøøøðøøøàÐØ ð #ð #�ð#Ø×%Ò%Ñ'Ô'Ð'Ð'øÝ ð ð ð Ø�Dðøøøð —L’L‘N”N�N�Nø�F—L’L‘N”N�N�NøøøØˆKØˆsT   Â3CÃC Ã#C Ã0'DÄ
D.Ä"D)Ä)D.Ä8EÅE2Å
EÅE2ÅEÅE2Å2Fc                 óì  — t          | j        ¦  «        }t          d¦  «        }t          ||¦  «        }t	          | j        |ddd| j        d|¬¦  «        \  }}}}d|d<   t          | j        ¦  «        |d<   | j        �t          | j        ¦  «        |d<   t          dt          t          t          | j        t          |i}| j                             | j        |||| j        t$          ||pdt&          g| j        ¬	¦
  «
        }	d}
	 t*                               |	||| j        t/          | j        d
z   d¦  «        | j        ¬¦  «        }
|
                     | j        ¦  «         nŽ# t4          $ r� 	 | j                             |	j        |	j        j        ¬¦  «         n<# t4          $ r/}t<                               d|	j        › d|› �¦  «         Y d}~nd}~ww xY w|
�|
                      ¦   «          ‚ w xY w| j!        |
_"        |
S )z6Start one host job and wait until its server is ready.rš   NFr¦  r  ÚSBX_HOST_MODEr2  r1  r§  r0   é   )rK  r2   r;  r%  r6  r7  rj  ri  r¬  )#r+  r'  r   r<   r¯  r  r]   r  r  r²  r³  rÌ  r™  rw   rµ  r°  r9  rž  r±  r¶  r  r4  rR  rÎ   r}  r  r  rk  rc   r8  r·  r¸  rh  r%  rF  )rO   r1   r2   r;  r¨  r»  r¼  r½  r¤  rK  r�  r  s               r;   r¬  zSandboxPool._boot_host  s9  € å# D¤IÑ.Ô.ˆÝ˜"‘”ˆÝ-¨h¸Ñ>Ô>ˆÝ5HØŒIØØØØØÔ+Ø"Ø'ð	6
ñ 	6
ô 	6
Ñ2ˆ�˜+ {ð $'ˆ�Ñ õ
 #& dÔ&=Ñ">Ô">ˆ�Ñð Œ>Ð%Ý'*¨4¬>Ñ':Ô':ˆG�OÑ$Ý ¥jµ)½ZÈÌÕT_ÐafÐgˆØŒi×ÒØ”*ØØØØ”;Ý(ØØÐ' 4Ý'Ð(Ø”oð  ñ 
ô 
ˆð +/ˆð	õ $×,Ò,ØØØ+Ø”IÝ # DÔ$;¸aÑ$?ÀÑ EÔ EØÔ0ð -ñ ô ˆFð ×Ò˜dÔ1Ñ2Ô2Ð2Ð2øÝð 	ð 	ð 	ðeØ”	×$Ò$¨C¬F¸c¼i¼nÐ$ÑMÔMÐMÐMøÝð eð eð eÝ—’ÐcÀÄÐcÐcÐ`aÐcÐcÑdÔdÐdÐdÐdÐdÐdÐdøøøøðeøøøàÐ!Ø—’‘”�Øð	øøøð Ô'ˆŒØˆs7   Ã?AE Å
G%Å%+FÆG%Æ
G
Æ%GÇ G%ÇG
Ç
G%rY  rV  r‰  c           
      óÞ  — ddi}|�||d<   |r||d<   	 |                      dd|¬¦  «                             ¦   «         }nf# t          t          j        f$ rM}|j        r‚ t                               d	|j        › d
|› �¦  «         |  	                    |¦  «         Y d}~dS d}~ww xY wd|_        | 
                    d¦  «        pg }t          | 
                    dd¦  «        ¦  «        s|s-| j        5  |j        |_        ddd¦  «         n# 1 swxY w Y   dS |d         }t          |j        › t           › |d         › �||d         dd| 
                    d¦  «        ¬¦  «        }	| j        |	_        |	S )u¡  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).
        Úcountr   NÚidle_timeout_secsr   r	  rÃ  ræ  z!Dropping unreachable cached host rÐ  TÚ	sandboxesÚrejectedr   rc   Fr/  rÄ  )r-  rq   r   rG  rŸ  rE  r·  r�  r  Ú
_drop_hostrr   rA   r  r7  rD  rh   rÉ  Ú_on_sandbox_killedr™  )
rO   rY  r   rV  Úbodyr±   r  r¸  rÁ  r›   s
             r;   rQ  zSandboxPool._create_one`  sç  € ð !(¨˜|ˆØÐ Ø(1ˆDÐ$Ñ%Øð 	ØˆD�‰Kð	Ø—<’< ¨¸d�<ÑCÔC×HÒHÑJÔJˆDˆDøÝ�fÔ.Ð/ð 	ð 	ð 	ØŒ}ð ØÝ�LŠLÐO¸T¼[ÐOÐOÈAÐOÐOÑPÔPÐPØ�OŠO˜DÑ!Ô!Ð!Ø�4�4�4�4�4øøøøð	øøøð ˆŒØ—H’H˜[Ñ)Ô)Ð/¨Rˆ	Ýˆt�xŠx˜
 AÑ&Ô&Ñ'Ô'ð 	¨yð 	Ø”ð *ð *Ø œM�”	ð*ð *ð *ñ *ô *ð *ð *ð *ð *ð *ð *øøøð *ð *ð *ð *à�4Ø˜Œ|ˆÝØ”+Ð:�}Ð:¨d°4¬jÐ:Ð:ØØ˜$”ZØØØŸ(š( 7Ñ+Ô+ð
ñ 
ô 
ˆð  Ô2ˆÔØˆs(   ”*? ¿B"ÁABÂB"Ã/DÄDÄDr›   c                 ó”   — | j         5  t          d|j        j        dz
  ¦  «        |j        _        ddd¦  «         dS # 1 swxY w Y   dS )z:Free the packing slot of a shared sandbox that was killed.r   r   N)r  rR  r”  rD  rž   s     r;   r»  zSandboxPool._on_sandbox_killed‡  s    € àŒZð 	Dð 	DÝ#& q¨'¬/Ô*>ÀÑ*BÑ#CÔ#CˆGŒOÔ ð	Dð 	Dð 	Dñ 	Dô 	Dð 	Dð 	Dð 	Dð 	Dð 	Dð 	Dð 	Døøøð 	Dð 	Dð 	Dð 	Dð 	Dð 	Ds   ˆ(=½AÁAc                 óÜ   ‡— | j         5  ˆfd„| j        D ¦   «         | _        | j                             ‰j        ¦  «         ddd¦  «         n# 1 swxY w Y   ‰                     ¦   «          dS )zFForget a host found dead this session (and mark it for cache pruning).c                 ó   •— g | ]}|‰u¯|‘Œ	S r`   r`   )rÏ   rM  rY  s     €r;   rÐ   z*SandboxPool._drop_host.<locals>.<listcomp>�  s   ø€ ÐCÐCÐC °Q¸d°]°]˜1°]°]°]r=   N)r  r  r*  r£  r  rh  rŠ  s    `r;   rº  zSandboxPool._drop_hostŒ  s©   ø€ àŒZð 	1ð 	1ØCÐCÐCÐC d¤kÐCÑCÔCˆDŒKØÔ×#Ò# D¤KÑ0Ô0Ð0ð	1ð 	1ð 	1ñ 	1ô 	1ð 	1ð 	1ð 	1ð 	1ð 	1ð 	1øøøð 	1ð 	1ð 	1ð 	1ð 	�
Š
‰Œˆˆˆs   ‰8AÁAÁAc                 óV  ‡— t          | j        | j        ¦  «        }|€dS t          | j        ¦  «        }t          j        ¦   «         }|j        D �]ÙŠ| j        5  d„ | j        D ¦   «         }ddd¦  «         n# 1 swxY w Y   ‰j	        |v s‰j
        ‰j        k    rŒMt          ‰¦  «        }|�mt                               d‰j	        › d| j        › d|› d�¦  «         | j        5  | j                             ‰j	        ¦  «         ddd¦  «         n# 1 swxY w Y   ŒË|‰j        z
  t$          k    r|                      ‰¦  «        sŒôt)          ‰j	        ‰j        | j        ‰j        ‰j        t3          |‰j        ¦  «        | j        t5          | j        dz   d¦  «        ‰j        ¬	¦	  «	        }‰j
        |_
        d
|_        | j        5  t;          ˆfd„| j        D ¦   «         ¦  «        r|                     ¦   «          n| j                             |¦  «         ddd¦  «         n# 1 swxY w Y   �ŒÛdS )u•  Adopt the pool's cached hosts without any HTTP (rebuilt from cached URL + nonce).

        The first thing that happens to a seeded host is an authenticated `POST`, so what the
        file says about *where* it lives is not taken on trust: the URL must be one only this
        job can have (`_cached_host_rejection`), and an entry older than `HOST_TRUST_TTL` is
        re-checked against the Jobs API first (`_confirm_cached_host`). A fresh entry â€” the
        `pool create` â†’ `create --pool` case the cache exists for â€” is used as is.

        Liveness stays best-effort: a seeded host is confirmed by its 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.
        Nc                 ó   — h | ]	}|j         ’Œ
S r`   rb  r]  s     r;   rÂ  z5SandboxPool._seed_hosts_from_cache.<locals>.<setcomp>ª  s   € Ð=Ð=Ð=¨˜œÐ=Ð=Ð=r=   zDropping cached host ú
 of pool 'z': it r+   r0   r´  rM  Fc              3   ó8   •K  — | ]}|j         ‰j         k    V — Œd S r�   rb  )rÏ   rY  Úchs     €r;   rù   z5SandboxPool._seed_hosts_from_cache.<locals>.<genexpr>Ã  s,   øè è € ÐHÐH°D�t”{ b¤iÒ/ÐHÐHÐHÐHÐHÐHr=   ) r   rw   r  r+  r'  rr  rj  r  r  r  rD  r7  Ú_cached_host_rejectionr·  r�  r*  r£  Ú
updated_atr   Ú_confirm_cached_hostr4  r8  r9  r:  r2   r<   rÎ   r  rE  rš  rh  rê  )rO   r6  r1   Únowr’  rƒ  r�  rÄ  s          @r;   rt  z"SandboxPool._seed_hosts_from_cache•  sç  ø€ õ   ¤	¨4Ô+>Ñ?Ô?ˆØˆ=ØˆFÝ# D¤IÑ.Ô.ˆÝŒi‰kŒkˆØ”+ð 	/ñ 	/ˆBØ”ð >ð >Ø=Ð=°´Ð=Ñ=Ô=�ð>ð >ð >ñ >ô >ð >ð >ð >ð >ð >ð >øøøð >ð >ð >ð >àŒy˜EÐ!Ð! R¤W°´Ò%;Ð%;ØÝ+¨BÑ/Ô/ˆFØÐ!Ý—’Ðd°R´YÐdÐdÈ$Ì)ÐdÐdÐ[aÐdÐdÐdÑeÔeÐeØ”Zð 7ð 7ØÔ'×+Ò+¨B¬IÑ6Ô6Ð6ð7ð 7ð 7ñ 7ô 7ð 7ð 7ð 7ð 7ð 7ð 7øøøð 7ð 7ð 7ð 7àØ�R”]Ñ"¥^Ò3Ð3¸D×<UÒ<UÐVXÑ<YÔ<YÐ3ØÝ#Ø”yØ”hØ”jØœØ”hÝ3°H¸b¼hÑGÔGØ”IÝ # DÔ$;¸aÑ$?ÀÑ EÔ EØœð
ñ 
ô 
ˆFð œ'ˆFŒKØ#ˆFŒOØ”ð /ð /ÝÐHÐHÐHÐH¸D¼KÐHÑHÔHÑHÔHð /Ø—L’L‘N”N�N�Nà”K×&Ò& vÑ.Ô.Ð.ð	/ð /ð /ñ /ô /ð /ð /ð /ð /ð /ð /øøøð /ð /ð /ð /ùð5	/ð 	/s7   ÁA6Á6A:	Á=A:	Ã! DÄD	ÄD	Ç AHÈH 	È#H 	rÄ  c           	      ó(  — | j         t          k    r#|                      ¦   «         €t          d¦  «        ‚	 | j                             |j        |j        ¬¦  «        }|j        pi }|j	        j
        dk    rd|j	        j
        › d�}n³|                     t          ¦  «        t          k    s#|                     t          ¦  «        | j        k    rd| j        › d�}na|                     t           ¦  «        |j        k    rd	}n;|                      |¦  «        sd
}n#t'          |¦  «        x}|j        k    rd|›d�}ndS nm# t*          j        $ r5}|j        j        dk    rt          d|j        › d�¦  «        |‚d}Y d}~n.d}~wt2          $ r}t          d|j        › d�¦  «        |‚d}~ww xY wt4                               d|j        › d| j        › d|› d�¦  «         | j        5  | j                             |j        ¦  «         ddd¦  «         n# 1 swxY w Y   dS )u/  Confirm an aged-out cache entry against the Jobs API before crediting it.

        Freshness is what the no-HTTP path rests on: the entry was written by this same
        principal minutes ago, so the job it names is almost certainly still the host it
        described. Past `HOST_TRUST_TTL` that argument weakens, and the entry becomes a hint
        that has to be checked â€” the job must still be running, still be labelled for *this*
        pool with the nonce the entry derives its token from, still pass the pool's adoption
        policy, and still expose exactly the cached URL. One round-trip, and only for entries
        the fast path would no longer be honest about.

        A definitive "no" prunes the entry; a transient failure aborts this attempt
        without losing the cached host.
        NzOCould not validate cached pool hosts: current user is unavailable; retry later.rj  rÆ  z its job is not running (status: rT   z+its job is not labelled as a host of pool 'ú'z!its job carries a different noncez&its job is not one this pool may adoptzits job exposes z, not the cached URLTrÿ   zCould not confirm cached host z; retry later.zits job no longer existszDropping stale cached host rÂ  rg  r+   F)r  r  rz  r   r'  rt  r  r8  r¤  ru  rv  rr   r³  rÌ  r™  rw   rµ  r2   r„  rP  r:  rG  ÚHTTPStatusErrorrs   r   r  r·  r�  r  r*  r£  )rO   rÄ  rK  r¤  rƒ  Úexposedr  s          r;   rÇ  z SandboxPool._confirm_cached_hostÈ  s‚  € ð Ô¥	Ò)Ð)¨d×.@Ò.@Ñ.BÔ.BÐ.JÝÐpÑqÔqÐqð	bØ”)×'Ò'¨r¬yÀBÄHÐ'ÑMÔMˆCØ”ZÐ% 2ˆFØŒzÔ 9Ò,Ð,ØO¸C¼JÔ<LÐOÐOÐO��Ø—’�JÑ'Ô'­9Ò4Ð4¸¿
º
Å:Ñ8NÔ8NÐRVÔR[Ò8[Ð8[ØSÀtÄyÐSÐSÐS��Ø—’�KÑ(Ô(¨B¬HÒ4Ð4Ø<��Ø—_’_ SÑ)Ô)ð ØA��Ý-¨cÑ2Ô2Ð2�'°r´{ÒBÐBØK¨GÐKÐKÐK��à�tøøÝÔ%ð 	0ð 	0ð 	0ØŒzÔ%¨Ò,Ð,Ý"Ð#]ÀBÄIÐ#]Ð#]Ð#]Ñ^Ô^ÐdeÐeØ/ˆFˆFˆFˆFˆFˆFøøøøÝð 	bð 	bð 	bÝÐYÀÄ	ÐYÐYÐYÑZÔZÐ`aÐaøøøøð	bøøøå�ŠÐ_°2´9Ð_Ð_ÈÌ	Ð_Ð_ÐV\Ð_Ð_Ð_Ñ`Ô`Ð`ØŒZð 	/ð 	/ØÔ×#Ò# B¤IÑ.Ô.Ð.ð	/ð 	/ð 	/ñ 	/ô 	/ð 	/ð 	/ð 	/ð 	/ð 	/ð 	/øøøð 	/ð 	/ð 	/ð 	/àˆus6   µDD9 Ä9F#Å+E8Å8F#ÆFÆF#Ç HÈHÈHrj  úList[_SandboxServer] | Nonec                 ó<  — | j         5  |€| j        n|}d„ |D ¦   «         }t          | j        ¦  «        }ddd¦  «         n# 1 swxY w Y   t	          | j        | j        | j        | j        | j	        | j
        | j        �t          | j        ¦  «        nd||¬¦	  «	         dS )a5  Persist the pool config + hosts (with their live counts) for next time.

        `hosts` overrides the tracked list, for the one case where they differ:
        `close()` persisting the hosts it could *not* cancel, since that record is
        the caller's only handle on a job that is still billing.
        Nc                 ó˜   — g | ]G}t          |j        |j        |j        |j        |j        |j        t          j        ¦   «         ¬ ¦  «        ‘ŒHS ))r  r8  r:  r2   r7  rD  rÆ  )r   r  r8  r:  r2   r7  rD  rr  r]  s     r;   rÐ   z+SandboxPool._save_cache.<locals>.<listcomp>û  s`   € ð ð ð ð õ Øœ;Øœ*Ø!œ]Øœ*Ø!œ]ØœÝ#œy™{œ{ðñ ô ðð ð r=   )Úcontextr9  rž  r  r  rŸ  rj  Údead_host_ids)r  r  r)  r*  r   rw   r  r9  rž  r  r  r  rC   )rO   rj  rí   rú   Údeads        r;   r@  zSandboxPool._save_cacheò  s  € ð ŒZð 	,ð 	,Ø$) M�T”[�[°uˆFðð ð #ðñ ô ˆGõ �tÔ*Ñ+Ô+ˆDð	,ð 	,ð 	,ñ 	,ô 	,ð 	,ð 	,ð 	,ð 	,ð 	,ð 	,øøøð 	,ð 	,ð 	,ð 	,õ 	ØŒIØÔ'Ø”*Ø”;Ø#Ô6Ø”nØBFÔBTÐB`Õ*¨4Ô+=Ñ>Ô>Ð>ÐfjØØð
	
ñ 
	
ô 
	
ð 
	
ð 
	
ð 
	
s   ˆ,A Á AÁA)r   r~  )r3   r  )r3   rˆ  r�   )rj  rÍ  r3   N)1rX   rY   rZ   r[   r  r5  r	  r  r]   rA   rB   r^   rŸ   r  r]  r   rD  r€  r	   r¾  rF  r_   r9  r_  rA  rh  rÔ  rÙ  r+  rz  r   r„  r‡  rO  rP  rŒ  r>  r¥  r4  r?  r¬  rQ  rh   r»  rº  rt  r   rÇ  r@  r`   r=   r;   r  r  !  s‡  € € € € € ð*ð *ð\ #ðD%ð "Ø"<ØØ $ØØ1EØ $Ø$Ø$Ø Ø#ðD%ð D%ð D%àðD%ð ð	D%ð
  ðD%ð ðD%ð ˜‘:ðD%ð �D‰jðD%ð ˜E‘k CÑ'¨$Ñ.ðD%ð ˜‘:ðD%ð ðD%ð ðD%ð �T‰zðD%ð ðD%ð 
ðD%ð D%ð D%ð D%ðP ð
 !%Ø$Ø ðC
ð C
ð C
àðC
ð ˜‘:ð	C
ð
 ðC
ð �T‰zðC
ð 
ðC
ð C
ð C
ñ „[ðC
ðJð ˜cð ¨$¨s¬)ð ð ð ð ð< &*Ø1EØ!&ð(+ð (+ð (+ð �#�s�(Œ^˜dÑ"ð(+ð ˜E‘k CÑ'¨$Ñ.ð	(+ð
 ð(+ð 
ð(+ð (+ð (+ð (+ðTLà�#�s�(Œ^˜dÑ"ðLð ˜E‘k CÑ'¨$Ñ.ðLð ð	Lð
 
ðLð Lð Lð Lð\ ð$˜3ð $ð $ð $ñ „Xð$ð
 ð:˜sð :ð :ð :ñ „Xð:ð
 ð9˜$˜sœ)ð 9ð 9ð 9ñ „Xð9ð
=ð =ð =ð =ð~ð ð ð ðoð oð oð oð'ð 'ð 'ð 'ðR	˜s T™zð 	ð 	ð 	ð 	ð˜gð ¨$ð ð ð ð ð gð °$ð ð ð ð ð ð ð ð ð'¨Ð-=Ô(>ð 'ÐCZð 'ð 'ð 'ð 'ð8' Tð 'ð 'ð 'ð 'ðR*/ð */ð */ð */ðX #ð ð ð ð ð8 GLð $ð $ð $¨ð $¸tð $ÐPTÐUcÔPdð $ð $ð $ð $ðL@˜Nð @ð @ð @ð @ðD%Ð 0ð %°t¸CÀ¸H´~ð %ÐRUÐX\ÑR\ð %Ðaqð %ð %ð %ð %ðND¨'ð D°dð Dð Dð Dð Dð
˜~ð °$ð ð ð ð ð1/ð 1/ð 1/ð 1/ðf( zð (°dð (ð (ð (ð (ðT 
ð  
ð  
ð  
ð  
ð  
ð  
r=   r  r9  c                 ó¼   — | €dS |                       ¦   «                              ¦   «         } dD ].}|                      |¦  «        r| t          |¦  «        d…         } Œ/| S )zŒCompare Docker images leniently: registries and tags get normalized
    server-side, and a mis-parse here must not stop a pool from working.N)z
docker.io/zindex.docker.io/zlibrary/)ÚstripÚlowerrþ  rU   )r9  Úprefixs     r;   Ú_normalize_imager×  	  sf   € ð €}ØˆtØ�KŠK‰MŒM×ÒÑ!Ô!€EØ@ð )ð )ˆØ×Ò˜FÑ#Ô#ð 	)Ø�#˜f™+œ+˜-˜-Ô(ˆEøØ€Lr=   Úurlc                óÞ   — t          | ¦  «        }|j        dk    rd|j        ›d�S |j        pd                     |› dt          › d�                     ¦   «         ¦  «        sd|› dt          › d	�S d
S )aC  Why `url` is not a URL we should send a sandbox job's credentials to.

    The hostname must be derived from the job id we already hold, so nothing but the
    client's own knowledge of which job it is talking to can decide where the credentials
    go. The domain is not hard-coded, so staging endpoints keep working.
    Úhttpszuses scheme z, not httpsr   ú--r+   zis not job z's port-z URLN)r   rú  Úhostnamerþ  r¶  rÕ  )rØ  r  Úparseds      r;   Ú_server_host_rejectionrÞ  !	  sŠ   € õ �c‰]Œ]€FØ„}˜ÒÐØ:˜fœmÐ:Ð:Ð:Ð:àŒOÐ!˜r×-Ò-°Ð.QÐ.QÕ;NÐ.QÐ.QÐ.Q×.WÒ.WÑ.YÔ.YÑZÔZð GØF˜VÐFÐFÕ-@ÐFÐFÐFÐFØˆ4r=   rK  c                 ó   — | j         �t          | j         j        pg ¦  «        ng }t          |¦  «        dk    rdt          |¦  «        › dt          › �S t          |d         | j        ¬¦  «        }|�d|d         ›d|› �ndS )zDWhy this Job's exposed URL is not one we should send credentials to.Nr   zexposes z' URL(s), expected exactly one for port r   rb  ú, which )ru  rØ   Úexpose_urlsrU   r¶  rÞ  rc   )rK  Úurlsrƒ  s      r;   Ú_server_url_rejectionrã  1	  sŽ   € à14´Ð1G�4�”
Ô&Ð,¨"Ñ-Ô-Ð-ÈR€DÝ
ˆ4�y„y�A‚~€~Øa�#˜d™)œ)ÐaÐaÕL_ÐaÐaÐaÝ# D¨¤G°C´FÐ;Ñ;Ô;€FØ5;Ð5GÐ1�d˜1”gÐ1Ð1¨Ð1Ð1Ð1ÈTÐQr=   rY  c                 óZ   — t          | j        | j        ¬¦  «        }|�d| j        ›d|› �ndS )ag  Why a cached host entry must not be rebuilt into a credentialed transport.

    Same reasoning as `_server_url_rejection`, for a URL that comes off the local disk
    instead of the Jobs API. Without this, the cache file gets to choose where the HF bearer
    and the derived host token are sent -- `http://127.0.0.1:1234` included -- and it gets to
    choose it *before* any API call could have contradicted it. Deriving the expected
    hostname from the entry's own `job_id` leaves it able to name only a job this client can
    independently identify, which is the same bar a discovered host has to clear.
    rb  Nznames rà  )rÞ  r:  r  )rY  rƒ  s     r;   rÅ  rÅ  :	  s>   € õ $ D¤M¸$¼+ÐFÑFÔF€FØ9?Ð9KÐ5�D”MÐ5Ð5¨VÐ5Ð5Ð5ÐQUÐUr=   r%  c                 óT   — t          j        | j        t          | ¦  «        |¬¦  «        S )zOThe local pool cache's security context for this endpoint/credential/namespace.)Úendpointr/  r)   )r   Úfor_credentialræ  r+  )r%  r)   s     r;   r  r  H	  s'   € åÔ&°´ÕDTÐUXÑDYÔDYÐenÐoÑoÔoÐor=   T)r†  r/  r}  rž  r†  c                óF  — |t           k    rdS |t          k    r3| j        }|�|j        €dS |€dS |j        |k    rd|j        p|j        › d�S |�)| j        �"| j        j        |k    rd| j        j        ›d|›�S | j        p| j        }|�(t          |¦  «        t          |¦  «        k    rd	|›d|›�S |�2t          | j
        ¦  «        |k    rd
t          | j
        ¦  «        ›d|›�S | j        �$t          | j        ¦  «        t          ¦   «         k    rdS |rt          | ¦  «        ndS )aú  Why this Job must not be adopted as one of our pool hosts, or `None`.

    Hosts are found by filtering Jobs on labels, and labels are set by whoever
    creates the Job -- so a label match says "this Job claims to be one of our
    hosts", not "this Job is one of our hosts". Anyone who can create a Job in
    the namespace can make that claim, copy the public nonce from a real host's
    labels, and receive the token derived for that host.

    Everything checked here is asserted by the backend rather than by the Job's
    creator: the initiator, the owner, the image, the flavor, the command, and
    the exposed URL. `initiator` is the load-bearing one -- there is no
    client-side way to set it -- and it is what makes `policy="own"` meaningful.
    z/host adoption is disabled (adopt_hosts='never')NzJthe Jobs API did not say who started it, so it cannot be confirmed as ourszHcould not resolve the current principal to compare against its initiatorz"started by a different principal (rT   zruns under namespace z, not zruns image zruns flavor z*does not run the sandbox bootstrap command)r  r  Ú	initiatorrc   rw   r8  rN  rO  r×  r]   rž  r¨  rØ   Ú_bootstrap_commandrã  )	rK  r/  r}  r)   r9  rž  r†  ré  Ú	job_images	            r;   r€  r€  M	  se  € ð. •ÒÐØ@Ð@à•ÒÐØ”Mˆ	ØÐ 	¤Ð 4Ø_Ð_ØÐØ]Ð]ØŒ<˜<Ò'Ð'ØY¸	¼Ð8VÈ)Ì,ÐYÐYÐYÐYàÐ ¤Ð!6¸3¼9¼>ÈYÒ;VÐ;VØL s¤y¤~ÐLÐL¸yÐLÐLÐLàÔ Ð0 C¤L€IØÐÕ-¨iÑ8Ô8Õ<LÈUÑ<SÔ<SÒSÐSØ9˜YÐ9Ð9°Ð9Ð9Ð9àÐ�c #¤*™oœo°Ò7Ð7ØA�c #¤*™oœoÐAÐA°vÐAÐAÐAð „{Ð�d 3¤;Ñ/Ô/Õ3EÑ3GÔ3GÒGÐGØ;Ð;ð *3Ð<Õ  Ñ%Ô%Ð%¸Ð<r=   c                 ó†   — t          | j        t          ¦  «        r| j        nt          ¦   «         }|st	          d¦  «        ‚|S )NzMA Hugging Face token is required to use sandboxes. Run `hf auth login` first.)r@   r/  r]   r   r   )r%  r/  s     r;   r+  r+  ƒ	  s?   € Ý# C¤I­sÑ3Ô3ÐDˆCŒIˆI½¹¼€EØð lÝÐjÑkÔkÐkØ€Lr=   r   r¡  r¢  rŸ  r£  r;  c                óÂ  — i |pi ¥dt          t          ¦  «        i¥}i |pi ¥d|i¥}	t          |pg ¦  «        }
|�t          t          |¦  «        ¦  «        |d<   |r||	d<   dt          › �}| j        › dt          j        › d|› �|d	<   t          |d
<   t          |d<   |
 	                    t          dt          j        t          d¬¦  «        ¦  «         t          ¦   «         ||	|
fS )a³  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. Either
    way the download is pinned to `SANDBOX_SERVER_SHA256` and verified before it runs.
    ÚSBX_PORTÚ	SBX_TOKENNr0  rI  zsbx-server-z	/buckets/z	/resolve/ÚSBX_SERVER_URLÚSBX_SERVER_SHA256ÚSBX_SERVER_MOUNTÚbucketT)r|   rí   Ú
mount_pathÚ	read_only)r]   r¶  rØ   rC   ÚSANDBOX_SERVER_SHA256ræ  r   ÚSANDBOX_SERVER_BUCKETÚ_SERVER_MOUNT_PATHrê  r   rê  )r%  r1   r   r¡  r¢  rŸ  r£  r;  r»  r¼  r½  Úserver_objects               r;   r¯  r¯  Š	  s  € ð( T # )¨ÐS¨j½#Õ>QÑ:RÔ:RÐSÐS€GØ"Q g m°Ð"Q°kÀ=Ð"QÐ"Q€KÝ�w�} "Ñ%Ô%€KØÐÝ&)Õ*;¸LÑ*IÔ*IÑ&JÔ&JˆÐ"Ñ#Øð +Ø"*ˆ�JÑð
 :Õ"7Ð9Ð9€MØ#&¤<Ð sÐ s½)Ô:YÐ sÐ sÐdqÐ sÐ s€GÐÑÝ#8€GÐÑ õ #5€GÐÑØ×ÒÝ�H¥YÔ%DÕQcÐosÐtÑtÔtñô ð õ ÑÔ ¨+°{ÐBÐBr=   c                  ó   — ddt           gS )z>The Job command every sandbox host and dedicated sandbox runs.z/bin/shz-c)Ú_BOOTSTRAP_DOWNLOADr`   r=   r;   rê  rê  µ	  s   € à�tÕ0Ð1Ð1r=   c                óÌ   — t          |j        t          ¦  «        r|j        ni }d|vr<|                      |j        |¬¦  «        j        pi }t          |t          ¦  «        r|ni }|S )z6Return a host job's env vars (where pool config lives)r2  rj  )r@   Úenvironmentr€  rt  rc   )r%  rK  r)   r   s       r;   r4  r4  º	  sf   € å'¨¬½Ñ>Ô>Ð
Fˆ#Œ/ˆ/ÀB€CØ˜SÐ Ð Ø�oŠo S¤V°yˆoÑAÔAÔMÐSÐQSˆÝ ¥TÑ*Ô*Ð2ˆcˆc°ˆØ€Jr=   r.  r,  c          	      ó,  — d}|t           k    r_	 |                      d¬¦  «                             d¦  «        }n4# t          $ r'}t                               d|› �¦  «         Y d}~nd}~ww xY wg }|                      dt          t          t          |i|¬¦  «        D ]=}t          ||||dd¬¦  «        }|€|c S |                     |j        › d	|› d
�¦  «         Œ>|r)t          d|› dd                     |¦  «        › d�¦  «        ‚t          d|› d�¦  «        ‚)aÙ  Return a running host job belonging to `pool_id`, found via the pool label.

    This one feeds `SandboxPool.connect`'s cold path, which rebuilds the pool's
    whole configuration (image, flavor, density, caps) from the job it returns --
    so an unvalidated match would let a Job in the namespace choose the image
    that the pool's *next* hosts boot. Image and flavor are unknown here (they
    are what we are about to learn), so this checks ownership and shape.
    NTrw  rc   rx  rÆ  r”  r|  rh  rT   z%Found host job(s) labelled for pool 'z' but none usable: rk  zp. Pass adopt_hosts='namespace' to SandboxPool if you intend to share hosts with other members of this namespace.rJ  rK  )r  ry  rr   r  r·  r¸  r˜  r³  rÌ  r™  r€  rê  rc   r   rï  )	r%  r,  r)   r/  Ú	principalr  r¹  rK  rƒ  s	            r;   r3  r3  Ã	  sš  € ð €IØ•ÒÐð	^ØŸ
š
¨˜
Ñ.Ô.×2Ò2°4Ñ8Ô8ˆIˆIøÝð 	^ð 	^ð 	^Ý�NŠNÐ\ÐYZÐ\Ð\Ñ]Ô]Ð]Ð]Ð]Ð]Ð]Ð]øøøøð	^øøøà€HØ�}Š}Ø¥*­i½ÀWÐ!MÐYbð ñ ô ð 0ð 0ˆõ !Ø˜¨YÀ)ÐSWÐ`dð
ñ 
ô 
ˆð ˆ>ØˆJˆJˆJØ�Š˜3œ6Ð.Ð. VÐ.Ð.Ð.Ñ/Ô/Ð/Ð/Øð 
Ýð)°Gð )ð )ÐPT×PYÒPYÐZbÑPcÔPcð )ð )ð )ñ
ô 
ð 	
õ
 ð	K¨7ð 	Kð 	Kð 	Kñô ð s   �)9 ¹
A*ÁA%Á%A*rp  rÍ  c          	      ó8  — |                       ||¬¦  «        }|j        pi }|                     t          ¦  «        }|�#|                     t          ¦  «        t
          k    rt          d|› d�¦  «        ‚|j        j        dk    r t          d|› d|j        j        › d�¦  «        ‚t          |t          d|dd¬	¦  «        }|�t          d|› d
|› d�¦  «        ‚t                               ||t          t          | ¦  «        |¦  «        | t          j        dz   ¬¦  «        S )z?Reattach to a running host job and return its server transport.rj  NrÅ  z is not a sandbox host.rÆ  zSandbox host rÇ  rq  r|  z+ does not look like a usable sandbox host: r+   rª  r«  )rt  r¤  rr   rµ  r³  rÌ  r   ru  rv  r€  r  r4  rR  r<   r+  r˜   r×   )r%  rÍ  r)   rK  r¤  r2   rƒ  s          r;   rË  rË  è	  s9  € à
�/Š/ ¸	ˆ/Ñ
BÔ
B€CØŒZÐ˜2€FØ�JŠJ•{Ñ#Ô#€EØ€}˜Ÿ
š
¥:Ñ.Ô.µ)Ò;Ð;ÝÐF +ÐFÐFÐFÑGÔGÐGØ
„zÔ˜9Ò$Ð$ÝÐe¨;ÐeÐeÐQTÔQ[ÔQaÐeÐeÐeÑfÔfÐfõ Ø•O°$À)ÐSWÐ`dðñ ô €Fð ÐÝÐc +ÐcÐcÐZ`ÐcÐcÐcÑdÔdÐdÝ×"Ò"ØØÝ+Õ,<¸SÑ,AÔ,AÀ5ÑIÔIØÝ$Ô9¸AÑ=ð #ñ ô ð r=   rŒ  c                 ó¾   — d| vr| |fS |                       dd¦  «        \  }}|r|rd|v rt          d| ›d�¦  «        ‚|�||k    rt          d|›d|›d�¦  «        ‚||fS )zPAccept `namespace/sandbox_id` ids (as shown in the Hub UI), like `hf jobs` does.rù  r   z?Sandbox id must be 'sandbox_id' or 'namespace/sandbox_id', got r+   Nz%Conflicting namespace: got namespace=z" but sandbox id implies namespace=)rÊ  r   )rŒ  r)   Úextracted_namespaceÚ	parsed_ids       r;   rÈ  rÈ  
  s±   € à
�*ÐÐØ˜9Ð$Ð$Ø%/×%5Ò%5°c¸1Ñ%=Ô%=Ñ"Ð˜Øð n ið n°3¸)Ð3CÐ3CÝÐlÐ]gÐlÐlÐlÑmÔmÐmØÐ Ð.AÒ!AÐ!AÝØ{°IÐ{Ð{ÐcvÐ{Ð{Ð{ñ
ô 
ð 	
ð Ð)Ð)Ð)r=   c                 ó†   — | j         j        pg D ]}dt          › d�|v r|c S Œt          d| j        › dt          › d�¦  «        ‚)NrÛ  r+   rÅ  z) does not expose the sandbox server port )ru  rá  r¶  r   rc   )rK  rØ  s     r;   rP  rP  
  se   € ØŒzÔ%Ð+¨ð ð ˆØ&Õ#Ð&Ð&Ð&¨#Ð-Ð-ØˆJˆJˆJð .å
Ðe˜cœfÐeÐeÕObÐeÐeÐeÑ
fÔ
fÐfr=   é   )r)   Úlimitr  c                óÎ   — 	 t          |                      ||¬¦  «        ¦  «        | d …         }n# t          $ r Y dS w xY w|r"dd                     d„ |D ¦   «         ¦  «        z   ndS )Nrj  r   z Last logs:
ú
c              3   ó    K  — | ]	}d |› �V — Œ
dS )z  Nr`   )rÏ   r  s     r;   rù   z!_tail_job_logs.<locals>.<genexpr>
  s(   è è € Ð&EÐ&E°t {¨D { {Ð&EÐ&EÐ&EÐ&EÐ&EÐ&Er=   )rØ   Úfetch_job_logsr  rï  )r%  r  r)   r  Úliness        r;   rx  rx  
  s‡   € ðÝ�S×'Ò'¨vÀÐ'ÑKÔKÑLÔLÈeÈVÈWÈWÔUˆˆøÝð ð ð ØˆrˆrðøøøàINÐVˆ?˜TŸYšYÐ&EÐ&E¸uÐ&EÑ&EÔ&EÑEÔEÑEÐEÐTVÐVs   ‚-0 °
>½>)yr8   r5   rq   rˆ   rñ   rr  Úconcurrent.futuresr   Ú
contextlibr   Údataclassesr   r   Úpathlibr   r¡  r   Útypingr	   r
   r   r   r   r   r   Úurllib.parser   rG  r   r   Ú_sandbox_cacher   r   r   r   r   r   Ú
_space_apir   Úerrorsr   r   r   Úhf_apir   r   Úutilsr   r    Úutils._parsingr!   Ú
get_loggerrX   r·  r¶  r²  r³  r´  rÌ  r™  rµ  Ú	frozensetr®  r  ÚSANDBOX_SERVER_VERSIONrö  r   r	  r±  r5  rl  ré  r  r  r  rÉ  rw  rT  rø  rû  r]   r<   rA   rB   rC   rE   rb   rv   r–   r˜   r^   r€  r  r�  r  r  r"  ÚAuthr$  r2  r4  rƒ  rh   r  r×  rÞ  rã  rÅ  r  r€  r+  rä   rØ   r¯  rê  r4  r3  rË  rÈ  rP  rx  r`   r=   r;   ú<module>r     sä	  ðð €€€Ø €€€Ø €€€Ø 	€	€	€	Ø Ð Ð Ð Ø €€€Ø 1Ð 1Ð 1Ð 1Ð 1Ð 1Ø %Ð %Ð %Ð %Ð %Ð %Ø (Ð (Ð (Ð (Ð (Ð (Ð (Ð (Ø Ð Ð Ð Ð Ð Ø Ð Ð Ð Ð Ð Ø MÐ MÐ MÐ MÐ MÐ MÐ MÐ MÐ MÐ MÐ MÐ MÐ MÐ MÐ MÐ MÐ MÐ MØ !Ð !Ð !Ð !Ð !Ð !à €€€à Ð Ð Ð Ð Ð ðð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð Ð Ð Ð Ð Ð Ø EÐ EÐ EÐ EÐ EÐ EÐ EÐ EÐ EÐ EØ "Ð "Ð "Ð "Ð "Ð "Ð "Ð "Ø %Ð %Ð %Ð %Ð %Ð %Ð %Ð %Ø *Ð *Ð *Ð *Ð *Ð *ð 
ˆÔ	˜HÑ	%Ô	%€ð Ð ð €à€
Ø€Ø€	ð €
ð !€à#˜) ]°JÀ
ÈKÐ$XÑYÔYÐ à€ð !Ð ØZÐ ð
 Ð àÐ ØÐ àÐ ð
 Ð ð -Ð ð
 €	Ø€Ø€à€ð AÐ ð Ð ð 'Ð ðÐ ðBc Cð c°ð c¸ð cð cð cð cð,$  e¡¨cÑ 1ð $°cð $ð $ð $ð $ð ðsð sð sð sð sñ sô sñ „ðsð& ð):ð ):ð ):ð ):ð ):ñ ):ô ):ñ „ð):ðX ðð ð ð ð ñ ô ñ „ðð ð dð ¨x¸Ô/Að ð ð ñ „ðð2eNð eNð eNð eNð eNñ eNô eNð eNðP	�s˜T #œY‘ð 	¨t°d©{ð 	¸tÀCÈÀH¼~ð 	ð 	ð 	ð 	ð˜6œ?ð ¨x¸¬~ð ð ð ð ðs ¤ð s°Dð sð sð sð sð V¤_ð ¸cð Àdð ð ð ð ð4ð ð ð ð �6”;ñ ô ð ð. ð ¨ð ð ð ð ðUkð Ukð Ukð Ukð Ukñ Ukô Ukð Ukðpð ð ð ð ñ ô ð ð"Oð Oð Oð Oð Oñ Oô Oð Oðdq
ð q
ð q
ð q
ð q
ñ q
ô q
ð q
ðh	˜C $™Jð 	¨3°©:ð 	ð 	ð 	ð 	ð ð °ð ¸¸d¹
ð ð ð ð ð R˜wð R¨3°©:ð Rð Rð Rð RðV ð V°°d±
ð Vð Vð Vð Vðp˜ð p¨#°©*ð p¸ð pð pð pð pð ð3=ð 3=ð 3=Ø	ð3=ð ð3=ð ˜‘*ð	3=ð
 �T‰zð3=ð �‰:ð3=ð �$‰Jð3=ð ð3=ð 	ˆ4�Zð3=ð 3=ð 3=ð 3=ðl˜%ð  Cð ð ð ð ð(CØ	ð(Càð(Cð 
ˆc�3ˆhŒ˜$Ñ	ð	(Cð
 �#�s�(Œ^˜dÑ"ð(Cð �&Œ\˜DÑ ð(Cð ˜‘+ Ñ# dÑ*ð(Cð ð(Cð ð(Cð ˆ4�Œ9�d˜3 ˜8”n d¨3°¨8¤n°d¸6´lÐBÔCð(Cð (Cð (Cð (CðV2˜D œIð 2ð 2ð 2ð 2ð
�5ð ˜wð °c¸D±jð ÀTÈ#ÈsÈ(Ä^ð ð ð ð ð NRÐajð "ð "ð "˜Uð "¨Sð "ÀÀdÁ
ð "Ð[^ð "Ðovð "ð "ð "ð "ðJ LPð ð ð �uð ¨3ð ¸cÀD¹jð ÐTbð ð ð ð ð4* #ð *°#¸±*ð *ÀÀsÈCÐRVÉJÀÔAWð *ð *ð *ð *ðg˜'ð g cð gð gð gð gð HLÐZ\ð Wð Wð W˜ð W sð W¸#À¹*ð WÐTWð WÐadð Wð Wð Wð Wð Wð Wr=   