o
    ;i6                    @   s  U 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Zd dl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 d dlmZmZmZmZmZmZmZ d dlZd dlmZ d dlmZ d d	lmZ d d
lm 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+m,Z, ddl-m.Z.m/Z/m0Z0m1Z1 ddl2m3Z3 ddl4m5Z5m6Z6 ddl7m8Z8 ddl9m:Z: ddl;m<Z< ddl=m>Z> ddl?m?Z?m@Z@mAZA ddlBmCZC ddlDmEZEmFZFmGZGmHZHmIZImJZJmKZK ddlLmMZMmNZNmOZO ddlPmQZQmRZR ddlSmTZTmUZU ddlVmWZW ddlXmYZY dd lZm[Z[ dd!l\m]Z] ej^rd dl_Z`d dlaZ`ed" Zbg d#g d#g d$g d%g d%d&Zcedebeeef f egd'< eehjid( Zjd)ZkG d*d+ d+Zlel Zmd,Zn	-	.	/djd0eef d1ebd2eod3eod4efd5effd6d7Zp		.	/dkd1ebd0eef d3eod4efd5eff
d8d9Zqd:efd1ebd5efd;d<Zrdld1ebd0eef d5effd=d>Zsd?ebd5effd@dAZtdBefdCefdDe
eefeeef f  d5eeef fdEdFZudGeeef d5eofdHdIZv				.	/dmdJeef dKeef dLeef dMeodNefd5effdOdPZwdQebd5ebfdRdSZxdTe
ef dUeegeof dVed5eeT fdWdXZyg ddfdYee
ef eegeof elf dZeeef d[ee dVeeeeff  fd\d]ZzG d^d_ d_Z{eG d`da daZ|dbefdce<d5e"j}fdddeZ~G dfdg dge&dhdiZe0eZdS )n    N)
CollectionSequence)	dataclass)
isfunction)PathPurePosixPath)AnyCallableLiteralOptionalUnioncastget_args)Message)StreamTerminatedError)Self)serialize_data_format)api_pb2   )LoadContext)_Objectlive_method_gen)Resolver)get_preferred_payload_format	serialize)TaskContextdeprecate_aio_usagesynchronize_apisynchronizer)MAX_OBJECT_SIZE_BYTES)extract_copy_command_patternsfind_dockerignore_file)FunctionInfo)validate_only_modal_volumes)_Client)_CloudBucketMount)configloggeruser_config_path)_get_environment_cached)ExecutionErrorInternalErrorInvalidErrorNotFoundErrorRemoteErrorServiceErrorVersionError)NON_PYTHON_FILESFilePatternMatcher
_ignore_fn)GPU_Tparse_gpu_config)_Mountpython_standalone_mount_name)_NetworkFileSystem)OutputManager)_Secret)_Volume)2023.122024.042024.102025.06PREVIEW)3.103.113.123.13z3.14z3.14t)rA   rB   rC   rD   )rA   rB   rC   )r@   r?   r>   r=   r<   SUPPORTED_PYTHON_SERIESbuilderz/modal_requirements.txtc                   @   s,   e Zd ZdefddZdedefddZdS )_AutoDockerIgnoreSentinelreturnc                 C   s
   t  dS )Nz.AUTO_DOCKERIGNORE)__name__self rL   ?/home/ubuntu/.local/lib/python3.10/site-packages/modal/image.py__repr__Y   s   
z"_AutoDockerIgnoreSentinel.__repr___c                 C   s   t d)Nz'This is only a placeholder. Do not call)NotImplementedError)rK   rO   rL   rL   rM   __call__\   s   z"_AutoDockerIgnoreSentinel.__call__N)rI   
__module____qualname__strrN   r   boolrQ   rL   rL   rL   rM   rG   X   s    rG   zmodal.Image.copy_* methods will soon be deprecated.

Use {replacement} instead, which is functionally and performance-wise equivalent.

See https://modal.com/docs/guide/modal-1-0-migration for more details.
TF python_versionbuilder_versionallow_micro_granularityallow_free_threadingcaller_namerH   c           
      C   s  | d u rdj tj  } }ndt| tstdt| j t	d| s)td| |s@| 
dr@|r7d| nd}td| | d	}t|d
krU|sUtd| dt|d
krb| 
drbdnd}|d  d	|d  | }t| }	||	vrtd| d|d|	d	| S )N{}.{}z2Python version must be specified as a string, not z^3(?:\.\d{1,2}){1,2}(rc\d*)?t?$zInvalid Python version: tzwith rV   z&Free threaded Python is not supported .   zaPython version must be specified as 'major.minor' for this interface; micro-level specification (z) is not valid.r   r   zUnsupported Python version: z. When using the z5 Image builder, Modal supports the following series: )formatsysversion_info
isinstancerT   r,   typerI   rematchendswithsplitlenrE   )
rW   rX   rY   rZ   r[   series_versioncontext
componentssuffixsupported_seriesrL   rL   rM   _validate_python_versionj   s8   

ro   c           	      C   sf   t || ||d}|d}t|dkr|S td| }tdd |D }dj| }|| }| d| S )NrZ   r[   r^      pythonc                 s   s     | ]}t |d dV  qdS )r^   r   N)tuplersplit).0vrL   rL   rM   	<genexpr>   s    z,_dockerhub_python_version.<locals>.<genexpr>r\   )ro   rh   ri   _base_image_configdictr`   )	rX   rW   rZ   r[   version_componentspython_versionsseries_to_micro_versionpython_series_requestedmicro_versionrL   rL   rM   _dockerhub_python_version   s   


r   groupc                 C   sB   t td }t|}W d    n1 sw   Y  ||  | S )Nzbase-images.json)openLOCAL_REQUIREMENTS_DIRjsonload)r   rX   fdatarL   rL   rM   rx      s   rx   c                 C   s:   |pt j}| dkr|drdnd}tt|  | d S )Nr<   rC   z.312rV   z.txt)ra   version
startswithrT   r   )rX   rW   rm   rL   rL   rM   _get_modal_requirements_path   s   
r   r   c                 C   s.   | dkrd}n	| dkrd}nd}| dt  S )Nr<   zpip installr=   z pip install --no-cache --no-depsz?uv pip install --system --compile-bytecode --no-cache --no-depsz -r )CONTAINER_REQUIREMENTS_PATH)r   prefixrL   rL   rM   _get_modal_requirements_command   s   r   function_namearg_nameargsc                 C   sV   dd }g }|D ] }t |tr|| q||r|| qt|  d| d|S )zTakes a sequence of strings, or string lists, and flattens it.

    Raises an error if any of the elements are not strings or string lists.
    c                 S   s   t | totdd | D S )Nc                 s       | ]}t |tV  qd S Nrc   rT   )ru   yrL   rL   rM   rw          z9_flatten_str_args.<locals>.is_str_list.<locals>.<genexpr>)rc   listall)xrL   rL   rM   is_str_list      z&_flatten_str_args.<locals>.is_str_listz: z must only contain strings)rc   rT   appendextendr,   )r   r   r   r   retr   rL   rL   rM   _flatten_str_args   s   
r   packagesc                 C   s   t dd | D  S )zLValidates that a list of packages does not contain any command-line options.c                 s       | ]}| d V  qdS )-Nr   )ru   pkgrL   rL   rM   rw      r   z%_validate_packages.<locals>.<genexpr>)any)r   rL   rL   rM   _validate_packages   s   r   
find_links	index_urlextra_index_urlpreextra_optionsc                 C   sT   d| fd|fd|fg}d dd |D }|r|d7 }|r(|r#|d7 }|| 7 }|S )Nz--find-linksz--index-urlz--extra-index-url c                 s   s0    | ]\}}|d ur| dt | V  qd S )Nr   shlexquote)ru   flagvaluerL   rL   rM   rw      s   . z)_make_pip_install_args.<locals>.<genexpr>z --pre)join)r   r   r   r   r   flagsr   rL   rL   rM   _make_pip_install_args   s   
r   server_versionc           	   	   C   s   t d }r|}d }tjv rd| d}ndt d}nd}| }ttt}||vrU|d ur3d}n|t|k r<d	}nd
}dh}|| }t	d|d|| d| d|S )Nimage_builder_versionMODAL_IMAGE_BUILDER_VERSIONz (based on your `z` environment variable)z& (based on your local config file at `z`)rV   z"or remove your local configurationz4your image builder version using the Modal dashboardz1your client library (pip install --upgrade modal)r@   zPThis version of the modal client supports the following image builder versions: z.

You are using z. Please update r^   )
r&   getosenvironr(   setr   ImageBuilderVersionminr0   )	r   local_config_versionr   env_varversion_sourcesupported_versionsupdate_suggestionpreview_versionssuggested_versionsrL   rL   rM   _get_image_builder_version   s8   r   docker_commands	ignore_fncontext_dirc                    sF   t | }|sdS t| dtdtf fdd}tj td|dS )a   
    Creates a context mount from a list of docker commands.

    1. Paths are evaluated relative to context_dir.
    2. First selects inclusions based on COPY commands in the list of commands.
    3. Then ignore any files as per the ignore predicate.
    NsourcerH   c                    s*   |   r	|  } | r| rdS dS )NTF)is_absoluterelative_to)r   r   r   
include_fnrL   rM   ignore_with_include(  s
   
z2_create_context_mount.<locals>.ignore_with_include/ignore)r    r2   r   rU   r6   _add_local_dirr   )r   r   r   copy_patternsr   rL   r   rM   _create_context_mount  s   r   r   dockerfile_cmdsdockerfile_pathc                    sV   rrt dtu rdtt f fdd}|S dtt f fdd}|S )Nz2Cannot provide both dockerfile and docker commandsrH   c                     sh    d u rt  nt    t } | rt| d  ntd}r+d n}t|| dS )Nutf8rL   r   r   )	r   cwdabsoluter!   r2   	read_text
splitlinesr3   r   )dockerignore_filer   cmds)r   r   r   rL   rM   auto_created_context_mount_fn>  s   
zE_create_context_mount_function.<locals>.auto_created_context_mount_fnc                     sD    d u rt  nt    rd n} t| t dS )Nr   r   )r   r   r   r   r   r   r3   r   r   r   r   r   rL   rM   r   O  s   )r,   AUTO_DOCKERIGNOREr   r6   )r   r   r   r   r   rL   r   rM   _create_context_mount_function3  s   r   c                   @   s>   e Zd ZdZejdfdddee fddZdej	fd	d
Z
dS )_ImageRegistryConfigmdmd:hiddenNregistry_auth_typez"api_pb2.RegistryAuthType.ValueTypesecretc                 C   s   || _ || _d S r   )r   r   )rK   r   r   rL   rL   rM   __init__\  s   
z_ImageRegistryConfig.__init__rH   c                 C   s"   t j| j| jr| jjdS ddS )NrV   )r   	secret_id)r   ImageRegistryConfigr   r   	object_idrJ   rL   rL   rM   	get_protoe  s   z_ImageRegistryConfig.get_proto)rI   rR   rS   __doc__r   REGISTRY_AUTH_TYPE_UNSPECIFIEDr   r:   r   r   r   rL   rL   rL   rM   r   Y  s    
	r   c                   @   s*   e Zd ZU ee ed< eeef ed< dS )DockerfileSpeccommandscontext_filesN)rI   rR   rS   r   rT   __annotations__ry   rL   rL   rL   rM   r   l  s   
 r   image_idclientc              
      s   dd  fdd}d}d u r@z| I d H  W n t ttfy; } z|d7 }|dkr1|W Y d }~nd }~ww d u sS )NrV   c                     s   t jdd}  jj| 2 z@3 d H W }|jr|j|jjr"|t	 }|j
D ]&}|jjs3|jjrD|jjt jks<J ||j q)|jrO||I d H  q)q6 t	   d S )N7   )r   timeoutlast_entry_id)r   ImageJoinStreamingRequeststubImageJoinStreamingunary_streamentry_idresultstatusr9   r   	task_logstask_progressposri   progress_typeIMAGE_SNAPSHOT_UPLOADupdate_snapshot_progressr   put_log_contentflush_lines)requestresponse
output_mgrtask_logr   r   r   result_responserL   rM   r   w  s$   
z'_image_await_build_result.<locals>.joinr   r   r_   )r/   r+   r   )r   r   r   retry_countexcrL   r	  rM   _image_await_build_results  s"   r  c                !   @   s  e Zd ZU dZeed< ee ed< ee	 ed< e
e	 ed< ee ed< dZeej ed< d	d
 ZdddZdee fddZdee fddZdde	defddZedej
e	 fddZdd Zedddddddddi dejdddeeed f  d eeegef  d!ee e!  d"eej" d#ed$ d%eej# d&ee$ d'eeg ee	 f  ded(eeef d)ee
e%ee&f   d*d+d,efd-d.Z'dde	d0e(ee)f dd fd1d2Z*dd3d4e(ee)f d0ededd fd5d6Z+dg d7d4e(ee)f d0eded8e(e
e ee)gef f dd f
d9d:Z,de-d7d;eded8e(e
e ee)gef f dd fd<d=Z.e/d>d?e0dd@edAedB de1j2fdCdDZ3ddGdHZ4dddddIdddddJ	dKe(eee f dLee dMee dNee dOedPededQeeeee f  d!ee e!  dRe5dd fdSdTZ6dddddIdddddU	dVedWedLee dMee dNee dOedPedRe5dQeeeee f  d!ee e!  dedd fdXdYZ7	dddddIdddddZd[edLee dMee dNee dOedPededQeeeee f  d!ee e!  dRe5dd fd\d]Z8g fdddddIdddddJ	d^ed_ee dLee dMee dNee dOedPededQeeeee f  d!ee e!  dRe5dd fd`daZ9ddddddIddddddbdKe(eee f dceee  dLee dMee dNee dOedPededdee dQeeeee f  d!ee e!  dRe5dd fdedfZ:	dddg g g dgdddddh
diedjee dkededlee dmee dnee doee dpedQeeeee f  d!ee e!  dRe5dd fdqdrZ;	sddddddIdddddt	duededveee  dweee  dxedPeddee dQeeeee f  d!ee e!  dRe5dd fdydzZ<i ddddde=d{d|e(eee f d}eeef dQeeeee f  d!ee e!  dRe5d~ee(e)ef  ded8e(e
e ee)gef f dd fddZ>dee dd fddZ?dee dd fddZ@ddddddde(eee f dQeeeee f  d!ee e!  deee(eeAf e&f  dRe5dedd fddZBe		ddee dedd fddZCdg ddddddKe(eee f dee dee dedQeeeee f  d!ee e!  dRe5dd fddZDe	ddededee dee dee f
ddZEe	dg ddddedee! dee dedee dd fddZFe	dg ddddedee! dee dedee dd fddZGe	dg ddddedee! dee dedee dd fddZHeddddddi e=dde(ee)f ded~ee(e)ef  dQeeeee f  d!ee e!  dRe5dee d(eeef d8e(e
e ee)gef f dd fddZIeddee dedd fddZJddddddKe(eee f dedQeeeee f  d!ee e!  dRe5dd fddZKddi i ddddddddi dddedeLf dQeeeee f  d!ee e!  dee(eeAf e(e&eMf f dee(eeAf eNf dRe(e5ee5 f deeO deeP dePdee dee(ee
e f  dede
eL deeeLf dedd f ddZQdeeef dd fddZRde(eeAf dd fddZSdee dd fddÄZTeUjVddń ZWeXdejYedf fddǄZZddAee[ de2fddɄZ\dS )_ImagezBase class for container images to run functions in.

    Do not construct this class directly; instead use one of its static factory methods,
    such as `modal.Image.debian_slim`, `modal.Image.from_registry`, or `modal.Image.micromamba`.
    force_buildinside_exceptions_serve_mounts_deferred_mounts_added_python_source_setN	_metadatac                 C   s&   g | _ t | _d| _t | _d| _d S )NrL   F)r  	frozensetr  r  r  r  rJ   rL   rL   rM   _initialize_from_empty  s
   
z_Image._initialize_from_emptyotherc                 C   s,   |j | _ |j| _|j| _|j| _|j| _d S r   )r  r  r  r  r  )rK   r  rL   rL   rM   _initialize_from_other  s
   z_Image._initialize_from_otherrH   c                 C      | j S r   )r  rJ   rL   rL   rM   _get_metadata  s   z_Image._get_metadatametadatac                 C   sD   t d}|| jkr| jD ]}||r t|tjsJ || _d S d S )Nr   )r&   r   r   r  rc   r   ImageMetadatar  )rK   r  env_image_idr  rL   rL   rM   _hydrate_metadata  s   



z_Image._hydrate_metadataFmountcopyc              	      sf   |r	| j ddS |  dddtdtdtt f fdd	}tj|d
 fddt d} j|_|S )Nr   remote_pathself2r  resolverload_contextexisting_object_idc                    s>   |    t jf | _ j rhnt B | _d S r   )_hydrate_from_otherrs   r  r  is_localr   )r#  r$  r%  r&  
base_imager  rL   rM   _load  s   
 z._Image._add_mount_layer_or_copy.<locals>._loadzImage(local files)c                      s    gS r   rL   rL   r)  rL   rM   <lambda>  s    z1_Image._add_mount_layer_or_copy.<locals>.<lambda>depsload_context_overrides)	_copy_mountr   r   r   rT   r  _from_loaderemptyr  )rK   r  r   r+  imgrL   r)  rM   _add_mount_layer_or_copy  s"   z_Image._add_mount_layer_or_copyc                 C   r  )a  Non-evaluated mount layers on the image

        When the image is used by a Modal container, these mounts need to be attached as well to
        represent the full image content, as they haven't yet been represented as a layer in the
        image.

        When the image is used as a base image for a new layer (that is not itself a mount layer)
        these mounts need to first be inserted as a copy operation (.copy_mount) into the image.
        )r  rJ   rL   rL   rM   _mount_layers  s   z_Image._mount_layersc                 C   s   | j rtdd S )Na]  An image tried to run a build step after using `image.add_local_*` to include local files.

Run `image.add_local_*` commands last in your image build to avoid rebuilding images with every local file change. Modal will then add these files to containers on startup instead, saving build time.
If you need to run other build steps after adding local files, set `copy=True` to copy the files directly into the image, at the expense of some added build time.

Example:

my_image = (
    Image.debian_slim()
    .add_local_file("data.json", copy=True)
    .run_commands("python -m mypak")  # this now works!
)
)r5  r,   rJ   rL   rL   rM   _assert_no_mount_layers  s
   z_Image._assert_no_mount_layersT)base_imagesdockerfile_functionsecrets
gpu_configbuild_functionbuild_function_inputimage_registry_configcontext_mount_functionr  
build_argsvalidated_volumes
_namespace_do_assert_no_mount_layersr7  r8  r9  r:  r;  zmodal._functions._Functionr<  r=  r>  r?  r@  rA  z%api_pb2.DeploymentNamespace.ValueTyperB  c                    s  d u ri d u rg d u rg 	d u rt  	
d u r!t 
D ]}t|ts.tdq#r;tdkr;tddtt f
fdd}dt	dt
d	td
tt f 	
fdd}d d}t	j|||t d}|_tjt gdd  D R  |_|S )NzDAll secrets of an image needs to be modal.Secret/AioSecret instancesr   z6Cannot run a build function with multiple base images!rH   c                     sT   t   t  } r| f7 } rjr| jf7 } D ]	\}}| |f7 } q| S r   )rs   valuesr   )r.  rO   vol)r7  r;  r=  r9  r@  rL   rM   _deps  s   

z _Image._from_args.<locals>._depsrK   r$  r%  r&  c           !         s(  r nd }|r| ||I d H   r  D ]}|  q|js%J t|jp*d|jI d H }tt|j	j
}t|}d u rGtg i d}	n|}	|	jsTsTtd|	jr]r]tddd  D }
g }|	j D ]%\}}t|d}|tj|| d W d    n1 sw   Y  qmrj}  }  }i ||}i }| D ],\}}t|rqzt| W n ty   td	| d
 j d Y qw |||< q|rt|nd}tj ! |d}nd}d }dd D }tj"|
|	j|dd D |r|jnd	
# t$%dt$%d||d}tj&|j||p)d|t$%dp1|t'j(%ddkt$%dd	}|jj)*|I d H }|j+}d }|j,j-rb|j,}|.dra|j/}nt0d|  t1||jI d H }|j,}|.dr~|j/}|j-tj2j3kr|j4rt5d| d|j4 d| d}t6% j7s|d7 }t5||j-tj2j8krd| d}|j4rd| d|j4 }t5||j-tj2j9krt5d| d |j-tj2j:krnt5d!|j- | ;||j| t< } D ]} || j=O }q|r|> r|?| t@|| _=d S )"NrV   r   r   u[   No commands were provided for the image — have you tried using modal.Image.debian_slim()?zSCannot provide both build function and Dockerfile commands in the same image layer!c                 S   s    g | ]\}}t j||jd qS ))
docker_tagr   )r   	BaseImager   )ru   rG  imagerL   rL   rM   
<listcomp>D  s    z4_Image._from_args.<locals>._load.<locals>.<listcomp>rb)filenamer   z(Skipping unserializable global variable z for z6. Changes to this variable won't invalidate the image.    )
definitionglobalsinputc                 S   s&   g | ]\}}t j||jd |jdqS )T)
mount_path	volume_idallow_background_commits	read_only)r   VolumeMountr   
_read_only)ru   pathvolumerL   rL   rM   rJ  s  s    c                 S   s   g | ]}|j qS rL   )r   )ru   r   rL   rL   rM   rJ    s    function_runtimefunction_runtime_debug)r7  dockerfile_commandsr   
secret_idscontext_mount_idr:  r=  runtimeruntime_debugr;  r?  volume_mountsr  #MODAL_IMAGE_ALLOW_GLOBAL_DEPLOYMENT1ignore_cache)	app_idrI  existing_image_idbuild_function_idr  	namespacerX   allow_global_deploymentrc  r  zWaiting for image %szImage build for z failed with the exception:
z) failed. See build logs for more details.zU (Hint: Use `modal.enable_output()` to see logs from the process building the Image.)z8 terminated due to external shut-down. Please try again.z: terminated due to external shut-down with the exception:
z? timed out. Please try again with a larger `timeout` parameter.zUnknown status %s!)Ar   rC  r6  rd  r)   environment_namer   r   r   	_settingsr   r   r   r   r,   itemsr   r   r   r   ImageContextFilereadr   	_get_infoget_globalsget_cls_var_attrsr   r   	Exceptionr'   warningr   BuildFunctionget_build_defImager   r&   r   ImageGetOrCreateRequestr   r   r   ImageGetOrCreater   r   r   HasFieldr  debugr  GenericResultGENERIC_STATUS_FAILURE	exceptionr.   r9   
is_enabledGENERIC_STATUS_TERMINATEDGENERIC_STATUS_TIMEOUTGENERIC_STATUS_SUCCESS_hydrater   r  r(  addr  )!rK   r$  r%  r&  context_mountrI  environmentr   rX   
dockerfilebase_images_pb2scontext_file_pb2srL  rW  r   rf  rO  attrsfiltered_globalskrv   build_function_globals_build_functionr`  image_definitionreqrespr   r  r   msglocal_mountsbaserB  rA  r7  r?  r;  r<  r>  r8  r  r:  r=  r9  r@  rL   rM   r+  &  s  








z _Image._from_args.<locals>._loadzImage()r-  c                 s   s    | ]}|j V  qd S r   )r  )ru   r  rL   rL   rM   rw     s    z$_Image._from_args.<locals>.<genexpr>)r   	GPUConfigr   rc   r:   r,   ri   r   r   r  r   r   r   rT   r1  r2  r  r  unionrC  r  )r7  r8  r9  r:  r;  r<  r=  r>  r  r?  r@  rA  rB  r   rE  r+  repobjrL   r  rM   
_from_args  s8   
:
 '
z_Image._from_argsr^   r"  c                    sD   t  ts	tddtdtffdd}tjd| i| fddd	S )
z%mdmd:hidden
        Internal
        z9The mount argument to copy has to be a Modal Mount objectr   rH   c                    s   dd  g}t |i dS )N	FROM basezCOPY . rF  r   r   r   r!  rL   rM   build_dockerfile  s   z,_Image._copy_mount.<locals>.build_dockerfiler  c                      s    S r   rL   rL   )r  rL   rM   r,    s    z$_Image._copy_mount.<locals>.<lambda>)r7  r8  r>  )rc   r6   r,   r   r   r  r  )rK   r  r"  r  rL   )r  r"  rM   r0    s   

z_Image._copy_mountr   
local_pathc                C   sF   t | s
td|dr|t|j }t||}| j||dS )a  Adds a local file to the image at `remote_path` within the container

        By default (`copy=False`), the files are added to containers on startup and are not built into the actual Image,
        which speeds up deployment.

        Set `copy=True` to copy the files into an Image layer at build time instead, similar to how
        [`COPY`](https://docs.docker.com/engine/reference/builder/#copy) works in a `Dockerfile`.

        copy=True can slow down iteration since it requires a rebuild of the Image and any subsequent
        build steps whenever the included files change, but it is required if you want to run additional
        build steps after this one.

        *Added in v0.66.40*: This method replaces the deprecated `modal.Image.copy_local_file` method.
        zJimage.add_local_file() currently only supports absolute remote_path valuesr   r  )	r   r   r,   rg   r   namer6   _from_local_filer4  )rK   r  r"  r   r  rL   rL   rM   add_local_file  s   
z_Image.add_local_file)r   r   r   c                C   s>   t | s
tdtjt|t |t|d}| j||dS )a  Adds a local directory's content to the image at `remote_path` within the container

        By default (`copy=False`), the files are added to containers on startup and are not built into the actual Image,
        which speeds up deployment.

        Set `copy=True` to copy the files into an Image layer at build time instead, similar to how
        [`COPY`](https://docs.docker.com/engine/reference/builder/#copy) works in a `Dockerfile`.

        copy=True can slow down iteration since it requires a rebuild of the Image and any subsequent
        build steps whenever the included files change, but it is required if you want to run additional
        build steps after this one.

        **Usage:**

        ```python
        from modal import FilePatternMatcher

        image = modal.Image.debian_slim().add_local_dir(
            "~/assets",
            remote_path="/assets",
            ignore=["*.venv"],
        )

        image = modal.Image.debian_slim().add_local_dir(
            "~/assets",
            remote_path="/assets",
            ignore=lambda p: p.is_relative_to(".venv"),
        )

        image = modal.Image.debian_slim().add_local_dir(
            "~/assets",
            remote_path="/assets",
            ignore=FilePatternMatcher("**/*.txt"),
        )

        # When including files is simpler than excluding them, you can use the `~` operator to invert the matcher.
        image = modal.Image.debian_slim().add_local_dir(
            "~/assets",
            remote_path="/assets",
            ignore=~FilePatternMatcher("**/*.py"),
        )

        # You can also read ignore patterns from a file.
        image = modal.Image.debian_slim().add_local_dir(
            "~/assets",
            remote_path="/assets",
            ignore=FilePatternMatcher.from_file("/path/to/ignorefile"),
        )
        ```

        *Added in v0.66.40*: This method replaces the deprecated `modal.Image.copy_local_dir` method.
        zIimage.add_local_dir() currently only supports absolute remote_path valuesr   r  )r   r   r,   r6   r   r   r3   r4  )rK   r  r"  r   r   r  rL   rL   rM   add_local_dir  s   ?z_Image.add_local_dirmodulesc                G   sN   t dd |D stdtj|d|i}| j||d}| jt|O  _|S )a  Adds locally available Python packages/modules to containers

        Adds all files from the specified Python package or module to containers running the Image.

        Packages are added to the `/root` directory of containers, which is on the `PYTHONPATH`
        of any executed Modal Functions, enabling import of the module by that name.

        By default (`copy=False`), the files are added to containers on startup and are not built into the actual Image,
        which speeds up deployment.

        Set `copy=True` to copy the files into an Image layer at build time instead. This can slow down iteration since
        it requires a rebuild of the Image and any subsequent build steps whenever the included files change, but it is
        required if you want to run additional build steps after this one.

        **Note:** This excludes all dot-prefixed subdirectories or files and all `.pyc`/`__pycache__` files.
        To add full directories with finer control, use `.add_local_dir()` instead and specify `/root` as
        the destination directory.

        By default only includes `.py`-files in the source modules. Set the `ignore` argument to a list of patterns
        or a callable to override this behavior, e.g.:

        ```py
        # includes everything except data.json
        modal.Image.debian_slim().add_local_python_source("mymodule", ignore=["data.json"])

        # exclude large files
        modal.Image.debian_slim().add_local_python_source(
            "mymodule",
            ignore=lambda p: p.stat().st_size > 1e9
        )
        ```

        *Added in v0.67.28*: This method replaces the deprecated `modal.Mount.from_local_python_packages` pattern.
        c                 s   r   r   r   )ru   modulerL   rL   rM   rw   m  r   z1_Image.add_local_python_source.<locals>.<genexpr>z2Local Python modules must be specified as strings.r   r  )r   r,   r6   _from_local_python_packagesr4  r  r   )rK   r   r   r  r  r3  rL   rL   rM   add_local_python_sourceH  s   %z_Image.add_local_python_source)i        zImage.from_idr   r   zmodal.client.Clientc              	      sp   t tt|}dtdtdtdtt	 f fdd}d d}tj
||t|d	d
} |_t tjt|S )zConstruct an Image from an id and look up the Image result.

        The ID of an Image object can be accessed using `.object_id`.
        rK   r$  r%  r&  c                    s6   |j jtj dI d H }| |j|j |j d S )Nr   )r   r   ImageFromIdr   ImageFromIdRequestr  r   r  )rK   r$  r%  r&  r  r  rL   rM   r+  }  s   z_Image.from_id.<locals>._loadzImage.from_id(r  )r   )r/  )typingr   r$   r   _translate_inr  r   r   r   rT   r1  
_object_idtyping_extensionsr   _translate_out)clsr   r   _clientr+  r  r  rL   r  rM   from_idt  s   "z_Image.from_idappmodal.app._Appc              	      s~   |j du r
tdt }t 4 I dH }t|d|j}|| |I dH  W d  I dH  | S 1 I dH s8w   Y  | S )a  Eagerly build an image.

        If your image was previously built, then this method will not rebuild your image
        and your cached image is returned.

        **Examples**

        ```python
        image = modal.Image.debian_slim().uv_pip_install("scipy", "numpy")

        app = modal.App.lookup("build-image", create_if_missing=True)
        with modal.enable_output():  # To see logs in your local terminal
            image.build(app)

        # Save the image id
        my_image_id = image.object_id

        # Reference the image with the id or uses it another context.
        built_image = modal.Image.from_id(my_image_id)
        ```

        Alternatively, you can pre-build a image and use it in a sandbox.

        ```python notest
        app = modal.App.lookup("sandbox-example", create_if_missing=True)

        with modal.enable_output():
            image = modal.Image.debian_slim().uv_pip_install("scipy")
            image.build(app)

        sb = modal.Sandbox.create("python", "-c", "import scipy; print(scipy)", app=app, image=image)
        print(sb.stdout.read())
        sb.terminate()
        ```

        **Note**

        For defining Modal functions, images are built automatically when deploying or running an App.
        You do not need to built the image explicitly:

        ```python notest
        app = modal.App()
        image = modal.Image.debian_slim()

        # No need to explicitly build the image for defining a function.
        @app.function(image=image)
        def f():
            ...
        ```

        NzUApp has not been initialized yet. Use the content manager `app.run()` or `App.lookup`)task_context)rd  r,   r   r   r   merged_with_root_load_contextr   )rK   r  r$  tcr%  rL   rL   rM   build  s   
4z_Image.buildrV   )	r   r   r   r   r   r  envr9  gpur   r   r   r   r   r   r  r  c       	            s   t dd|
s
| S tstddtdtf fdd}|p%g }|r1g |t|}t|	}tj	d| i|| j
p?|||d	S )
a  Install a list of Python packages using pip.

        **Examples**

        Simple installation:
        ```python
        image = modal.Image.debian_slim().pip_install("click", "httpx~=0.23.3")
        ```

        More complex installation:
        ```python
        image = (
            modal.Image.from_registry(
                "nvidia/cuda:12.2.0-devel-ubuntu22.04", add_python="3.11"
            )
            .pip_install(
                "ninja",
                "packaging",
                "wheel",
                "transformers==4.40.2",
            )
            .pip_install(
                "flash-attn==2.5.8", extra_options="--no-build-isolation"
            )
        )
        ```
        pip_installr   zoPackage list for `Image.pip_install` cannot contain other arguments; try the `extra_options` parameter instead.r   rH   c                    sT   t t}t }dd| d| g}| dkr$dd |D }t|i dS )Nr  RUN python -m pip install r   r<   c                 S      g | ]}|  qS rL   stripru   cmdrL   rL   rM   rJ        z@_Image.pip_install.<locals>.build_dockerfile.<locals>.<listcomp>rF  )r   r   sortedr   r   )r   package_args
extra_argsr   r   r   r   r   pkgsr   rL   rM   r    s   z,_Image.pip_install.<locals>.build_dockerfiler  r7  r8  r  r:  r9  )r   r   r,   r   r   r:   	from_dictr5   r  r  r  )rK   r   r   r   r   r   r  r  r9  r  r   r  r:  rL   r  rM   r    s&   ( z_Image.pip_install)	r   r   r   r   r   r  r  r9  r  repositoriesgit_userc       
      	      s(  |	st d|rg |	t|}	g }g D ]:}t|ts#|| |d}|d dkr:d| d|  q|d dkrLd| d|  q|| q|ret t| d	t d
| dddd |	D dt	dt
f fdd}t|}tjd| i||	|| jp|
dS )a,  
        Install a list of Python packages from private git repositories using pip.

        This method currently supports Github and Gitlab only.

        - **Github:** Provide a `modal.Secret` that contains a `GITHUB_TOKEN` key-value pair
        - **Gitlab:** Provide a `modal.Secret` that contains a `GITLAB_TOKEN` key-value pair

        These API tokens should have permissions to read the list of private repositories provided as arguments.

        We recommend using Github's ['fine-grained' access tokens](https://github.blog/2022-10-18-introducing-fine-grained-personal-access-tokens-for-github/).
        These tokens are repo-scoped, and avoid granting read permission across all of a user's private repos.

        **Example**

        ```python
        image = (
            modal.Image
            .debian_slim()
            .pip_install_private_repos(
                "github.com/ecorp/private-one@1.0.0",
                "github.com/ecorp/private-two@main"
                "github.com/ecorp/private-three@d4776502"
                # install from 'inner' directory on default branch.
                "github.com/ecorp/private-four#subdirectory=inner",
                git_user="erikbern",
                secrets=[modal.Secret.from_name("github-read-private")],
            )
        )
        ```
        zsNo secrets provided to function. Installing private packages requires tokens to be passed via modal.Secret objects.r   r   z
github.comzgit+https://z:$GITHUB_TOKEN@z
gitlab.comz:$GITLAB_TOKEN@z out of z2 given repository refs are invalid. Invalid refs: z. ,c                 S   s$   g | ]}t |d r|jnt|qS )app_name)hasattrr  rT   )ru   srL   rL   rM   rJ  U     $ z4_Image.pip_install_private_repos.<locals>.<listcomp>r   rH   c                    s   dg}t dd D r|d d t dd D r'|d d t |dg | fd	d
D  | dkrLdd
 |D }t|i dS )Nr  c                 s   r   )githubNr   ru   rrL   rL   rM   rw   Y  r   zM_Image.pip_install_private_repos.<locals>.build_dockerfile.<locals>.<genexpr>zgRUN bash -c "[[ -v GITHUB_TOKEN ]] || (echo 'GITHUB_TOKEN env var not set by provided modal.Secret(s): z' && exit 1)"c                 s   r   )gitlabNr   r  rL   rL   rM   rw   ^  r   zgRUN bash -c "[[ -v GITLAB_TOKEN ]] || (echo 'GITLAB_TOKEN env var not set by provided modal.Secret(s): z,RUN apt-get update && apt-get install -y gitc                    s   g | ]
}d | d  qS )zRUN python3 -m pip install "z" rL   )ru   urlr  rL   rM   rJ  f  s    zN_Image.pip_install_private_repos.<locals>.build_dockerfile.<locals>.<listcomp>r<   c                 S   r  rL   r  r  rL   rL   rM   rJ  h  r  rF  )r   r   r   r   r   r  r   r   r   r   install_urlsr   r  secret_namesr  rM   r  W  s&   z:_Image.pip_install_private_repos.<locals>.build_dockerfiler  )r7  r8  r9  r:  r  )r,   r:   r  rc   rT   r   rh   ri   r   r   r   r5   r  r  r  )rK   r  r   r   r   r   r   r  r  r9  r  r  invalid_reposrepo_refpartsr  r:  rL   r  rM   pip_install_private_repos  sB   .


$z _Image.pip_install_private_repos)r   r   r   r   r  r  r9  r  requirements_txtc                   s`   |	pg }	|rg |	t |}	dtdtf fdd}tjd| i|| jp)|t|
|	dS )zGInstall a list of Python packages from a local `requirements.txt` file.r   rH   c                    s~   t j}d|i}| dkrdnd}rd n|}t }ddd| d| g}| dkr9d	d
 |D }t||dS )Nz/.requirements.txtr<   r   rV   z -f r  z*COPY /.requirements.txt /.requirements.txtz/RUN python -m pip install -r /.requirements.txtc                 S   r  rL   r  r  rL   rL   rM   rJ    r  zR_Image.pip_install_from_requirements.<locals>.build_dockerfile.<locals>.<listcomp>rF  )r   rW  
expanduserr   r   )r   requirements_txt_pathr   null_find_links_argfind_links_argr  r   r   r   r   r   r   r  rL   rM   r    s   z>_Image.pip_install_from_requirements.<locals>.build_dockerfiler  r  r:   r  r   r   r  r  r  r5   )rK   r  r   r   r   r   r   r  r  r9  r  r  rL   r  rM   pip_install_from_requirementsu  s    z$_Image.pip_install_from_requirementspyproject_tomloptional_dependenciesc       	            sb   |
pg }
|	rg |
t |	}
dtdtf fdd}tjd| i|| jp*||
t|dS )aQ  Install dependencies specified by a local `pyproject.toml` file.

        `optional_dependencies` is a list of the keys of the
        optional-dependencies section(s) of the `pyproject.toml` file
        (e.g. test, doc, experiment, etc). When provided,
        all of the packages in each listed section are installed as well.
        r   rH   c           
         s   dd l }|tj}g }d|vsd|d vrd}t|||d d  r@|d d }D ]}||v r?|||  q2t }t	t
|}dd| d| g}	| d	krdd
d |	D }	t|	i dS )Nr   projectdependenciesa  No [project.dependencies] section in pyproject.toml file. If your pyproject.toml instead declares [tool.poetry.dependencies], use `Image.poetry_install_from_file()`. See https://packaging.python.org/en/latest/guides/writing-pyproject-toml for further file format guidelines.optional-dependenciesr  r  r   r<   c                 S   r  rL   r  r  rL   rL   rM   rJ    r  zO_Image.pip_install_from_pyproject.<locals>.build_dockerfile.<locals>.<listcomp>rF  )tomlr   r   rW  r  
ValueErrorr   r   r   r   r  r   )
r   r  r&   r  r  	optionalsdep_group_namer  r  r   r   r   r   r   r  r   r  rL   rM   r    s(   z;_Image.pip_install_from_pyproject.<locals>.build_dockerfiler  r7  r8  r  r9  r:  r  )rK   r  r  r   r   r   r   r   r  r  r9  r  r  rL   r  rM   pip_install_from_pyproject  s   " z!_Image.pip_install_from_pyproject)requirementsr   r   r   r   r   r  
uv_versionr  r9  r  r  r  c             	      s   |
pg }
|	rg |
t |	}
tdd|du sttr#p!g ntds-s-| S ts5tddtdtf fdd	}t	j
d
| i|| jpQ|t||
dS )a  Install a list of Python packages using uv pip install.

        **Examples**

        Simple installation:
        ```python
        image = modal.Image.debian_slim().uv_pip_install("torch==2.7.1", "numpy")
        ```

        This method assumes that:
        - Python is on the `$PATH` and dependencies are installed with the first Python on the `$PATH`.
        - Shell supports backticks for substitution
        - `which` command is on the `$PATH`

        Added in v1.1.0.
        uv_pip_installr   Nz.requirements must be None or a list of stringszrPackage list for `Image.uv_pip_install` cannot contain other arguments; try the `extra_options` parameter instead.r   rH   c                    sr  dg}d 	d u r| d  d n| d	 d  d ddg}i }r2| d	t  r?| d
t  rL| dt  rS| d rZ|  rdtdtdtf fddfddtD }ddd |D }| | |dd |D  |	dd |D  |dd t
D  d|}| d  d|  t||dS )Nr  /.uv,COPY --from=ghcr.io/astral-sh/uv:latest /uv /uv!COPY --from=ghcr.io/astral-sh/uv: /uv z--python $(command -v python)--compile-bytecodez--find-links z--index-url z--extra-index-url z--prerelease allowidxr  rH   c                    s@   t j|}t j|}|d|  d|   d|  d| dS )Nz/.rO   r   )r  context_path	dest_path)r   rW  r  basename)r  r  r  r  )UV_ROOTrL   rM   _generate_paths4  s   zH_Image.uv_pip_install.<locals>.build_dockerfile.<locals>._generate_pathsc                    s   g | ]	\}} ||qS rL   rL   )ru   r  r  )r  rL   rM   rJ  C      zC_Image.uv_pip_install.<locals>.build_dockerfile.<locals>.<listcomp>r   c                 s   s    | ]
}d |d  V  qdS )z--requirements r   NrL   ru   r  rL   rL   rM   rw   D  s    zB_Image.uv_pip_install.<locals>.build_dockerfile.<locals>.<genexpr>c                 S   s$   g | ]}d |d  d|d  qS )COPY r  r   r   rL   r  rL   rL   rM   rJ  G  r  c                 S   s   i | ]	}|d  |d qS )r  r  rL   r  rL   rL   rM   
<dictcomp>H  r  zC_Image.uv_pip_install.<locals>.build_dockerfile.<locals>.<dictcomp>c                 s   s    | ]}t |V  qd S r   r   )ru   prL   rL   rM   rw   J  r   RUN z/uv pip install rF  )r   r   r   intrT   ry   	enumerater   r   updater  r   )r   r   uv_pip_argsr   requirement_pathsrequirements_cliuv_pip_args_joinedr   r   r   r   r  r   r  r  )r  r  rM   r    s8   



z/_Image.uv_pip_install.<locals>.build_dockerfiler  r  )r:   r  r   rc   r   r,   r   r   r   r  r  r  r5   )rK   r  r   r   r   r   r   r  r  r  r9  r  r   r  rL   r  rM   r    s*    
$9z_Image.uv_pip_installlatest)
ignore_lockfiler  with_withoutonlypoetry_versionold_installerr  r9  r  poetry_pyproject_tomlpoetry_lockfiler  r  r  r  r  r  c       
      	      sd   |pg }|
rg |t |
}dtdtf fdd}tjd| i|| jp+||t|dS )a  Install poetry *dependencies* specified by a local `pyproject.toml` file.

        If not provided as argument the path to the lockfile is inferred. However, the
        file has to exist, unless `ignore_lockfile` is set to `True`.

        Note that the root project of the poetry project is not installed, only the dependencies.
        For including local python source files see `add_local_python_source`

        Poetry will be installed to the Image (using pip) unless `poetry_version` is set to None.
        Note that the interpretation of `poetry_version="latest"` depends on the Modal Image Builder
        version, with versions 2024.10 and earlier limiting poetry to 1.x.
        r   rH   c                    s0  dt ji}dg}d ur)dkr| dkrdnd}nd }|d| g7 }r0|d	g7 } sXd u rOtjd
 }| sKtd|  d| |d< |dg7 }d}| dkrbd| }rn|dd	 7 }rz|dd	 7 }r|dd	 7 }|d7 }|ddd|g7 }t
||dS )N/.pyproject.tomlr  r  r>   z~=1.7rV   z==z RUN python -m pip install poetryz2RUN poetry config experimental.new-installer falsezpoetry.lockz,poetry.lock not found at inferred location: zB. If a lockfile is not needed, `ignore_lockfile=True` can be used.z/.poetry.lockz*COPY /.poetry.lock /tmp/poetry/poetry.lockzpoetry install --no-rootr<   z  z --with r  z --without z --only z
 --compilez0COPY /.pyproject.toml /tmp/poetry/pyproject.tomlzRUN cd /tmp/poetry && \ z.  poetry config virtualenvs.create false && \ rF  )r   rW  r  r   parentexistsr-   r   as_posixr   r   )r   r   r   poetry_specr  install_cmdr  r  r  r  r  r  r  r  rL   rM   r  }  sH   


z9_Image.poetry_install_from_file.<locals>.build_dockerfiler  r  r  )rK   r  r  r  r  r  r  r  r  r  r  r9  r  r  rL   r!  rM   poetry_install_from_fileY  s    $3z_Image.poetry_install_from_file./)	r  groupsextrasfrozenr   r  r  r9  r  uv_project_dirr$  r%  r&  c       	            s   |	pg }	|rg |	t |}	dtt fdd}|d|ddtdtffdd	 dtdtf fd
d}tjd| i|| jpI||	t	|
dS )a  Creates a virtual environment with the dependencies in a uv managed project with `uv sync`.

        **Examples**
        ```python
        image = modal.Image.debian_slim().uv_sync()
        ```

        The `pyproject.toml` and `uv.lock` in `uv_project_dir` are automatically added to the build context. The
        `uv_project_dir` is relative to the current working directory of where `modal` is called.

        NOTE: This does *not* install the project itself into the environment (this is equivalent to the
        `--no-install-project` flag in the `uv sync` command) and you would be expected to add any local python source
        files using `Image.add_local_python_source` or similar methods after this call.

        This ensures that updates to your project code wouldn't require reinstalling third-party dependencies
        after every change.

        uv workspaces are currently not supported.

        Added in v1.1.0.
        rH   c                 S   s(   | d u rg S t | tr| S t| d)Nz" must be None or a list of strings)rc   r   r,   )rk  r  rL   rL   rM   _normalize_items  s
   
z(_Image.uv_sync.<locals>._normalize_itemsr$  r%  r  r   c           	   
      s|  t j| std|  ddd l}t| }||}W d    n1 s&w   Y  d|v rAd|d v rAd|d d v rAtd|dkrGd S z|d	 d
 }W n tyf } ztd| d|  dd }~ww D ]}d|v r}||d v r}||d | 7 }qiD ]}d	|v rd|d	 v r||d	 d v r||d	 d | 7 }qt	d dt
f fddtfdd|D stdd S )Nz	Expected z	 to existr   tooluv	workspacezuv workspaces are not supportedr>   r  r  z)Invalid pyproject.toml file: missing key z in zZ. See https://packaging.python.org/en/latest/guides/writing-pyproject-toml for guidelines.zdependency-groupsr  z^[\w-]+rH   c                    s     | }|r|dS dS )Nr   rV   )rf   r   )packagem)PACKAGE_REGEXrL   rM   _extract_package  s   
zG_Image.uv_sync.<locals>._check_pyproject_toml.<locals>._extract_packagec                 3   s    | ]	} |d kV  qdS )modalNrL   )ru   
dependency)r/  rL   rM   rw     s    z@_Image.uv_sync.<locals>._check_pyproject_toml.<locals>.<genexpr>z[Image builder version <= 2024.10 requires modal to be specified in your pyproject.toml file)r   rW  r  r,   r  r   r   KeyErrorre   compilerT   r   )	r  r   r  r   pyproject_toml_contentr  er   extra)r%  r$  )r.  r/  rM   _check_pyproject_toml  sL   

z-_Image.uv_sync.<locals>._check_pyproject_tomlc                    sN  t j}t j|d}d}d| ddg}D ]
}|d|  qD ]
}|d|  q&r8| dg}d u rI|d	| d
 n|d d| d
 i } ||  ||d< |d| d t j|d}	t j|	r|	|d< |d| d r|d d| }
|d| d|
 d| dg7 }t||dS )Nzpyproject.tomlr  z
--project=z--no-install-workspacer  z--group=z--extra=r  r  r  r  r  r  zCOPY /.pyproject.toml z/pyproject.tomlzuv.lockz	/.uv.lockzCOPY /.uv.lock z/uv.lockz--frozenr   r	  z	/uv sync z	ENV PATH=z/.venv/bin:$PATHrF  )r   rW  r  r   r   r  r  r   )r   uv_project_dir_r  r  uv_sync_argsr   r6  r   r   uv_lockuv_sync_args_joinedr7  r   r%  r&  r$  r'  r  rL   rM   r  "  sB   



z(_Image.uv_sync.<locals>.build_dockerfiler  r  )
r:   r  r   rT   r   r   r  r  r  r5   )rK   r'  r  r$  r%  r&  r   r  r  r9  r  r(  r  rL   r<  rM   uv_sync  s   $

"76z_Image.uv_sync)r   r  r9  r  r   r  r   r[  r   r   c          
   
      sx   t dd|  s
| S |pg }|rg |t|}dtdtf fdd}	tjd| i|	|t|t| |d| j	p9|dS )	a=  
        Extend an image with arbitrary Dockerfile-like commands.

        **Usage:**

        ```python
        from modal import FilePatternMatcher

        # By default a .dockerignore file is used if present in the current working directory
        image = modal.Image.debian_slim().dockerfile_commands(
            ["COPY data /data"],
        )

        image = modal.Image.debian_slim().dockerfile_commands(
            ["COPY data /data"],
            ignore=["*.venv"],
        )

        image = modal.Image.debian_slim().dockerfile_commands(
            ["COPY data /data"],
            ignore=lambda p: p.is_relative_to(".venv"),
        )

        image = modal.Image.debian_slim().dockerfile_commands(
            ["COPY data /data"],
            ignore=FilePatternMatcher("**/*.txt"),
        )

        # When including files is simpler than excluding them, you can use the `~` operator to invert the matcher.
        image = modal.Image.debian_slim().dockerfile_commands(
            ["COPY data /data"],
            ignore=~FilePatternMatcher("**/*.py"),
        )

        # You can also read ignore patterns from a file.
        image = modal.Image.debian_slim().dockerfile_commands(
            ["COPY data /data"],
            ignore=FilePatternMatcher.from_file("/path/to/dockerignore"),
        )
        ```
        r[  r   rH   c                    s   t dg dS )Nr  rF  r  r   r   r   rL   rM   r    s   z4_Image.dockerfile_commands.<locals>.build_dockerfiler  )r   r   r   )r7  r8  r9  r:  r>  r  )
r   r:   r  r   r   r  r  r5   r   r  )
rK   r   r  r9  r  r   r  r   r[  r  rL   r?  rM   r[  `  s"   4z_Image.dockerfile_commandsentrypoint_commandsc                 C   `   t |trtdd |D stdtdd|}|r#dd| d nd}d	| d
}| |S )z!Set the ENTRYPOINT for the image.c                 s   r   r   r   ru   r   rL   rL   rM   rw     r   z$_Image.entrypoint.<locals>.<genexpr>z.entrypoint_commands must be a list of strings.
entrypointr@  "", "rV   zENTRYPOINT []rc   r   r   r,   r   r   r[  )rK   r@  args_strdockerfile_cmdrL   rL   rM   rC       
z_Image.entrypointshell_commandsc                 C   rA  )z&Overwrite default shell for the image.c                 s   r   r   r   rB  rL   rL   rM   rw     r   z_Image.shell.<locals>.<genexpr>z)shell_commands must be a list of strings.shellrK  rD  rE  rV   zSHELL [rF  rG  )rK   rK  rH  rI  rL   rL   rM   rL    rJ  z_Image.shell)r  r9  volumesr  r  r   rM  c             	      sr   |pg }|rg |t |}tdd|  s| S dtdtf fdd}tjd| i||t|| jp2|t	|dd	S )
z5Extend an image with a list of shell commands to run.run_commandsr   r   rH   c                    s   t dgdd  D  i dS )Nr  c                 S   s   g | ]}d | qS )r	  rL   r  rL   rL   rM   rJ    s    zA_Image.run_commands.<locals>.build_dockerfile.<locals>.<listcomp>rF  r  r>  r   rL   rM   r    r   z-_Image.run_commands.<locals>.build_dockerfiler  zImage.run_commands)r7  r8  r9  r:  r  r@  )
r:   r  r   r   r   r  r  r5   r  r#   )rK   r  r9  rM  r  r  r   r  rL   r   rM   rN    s   z_Image.run_commandsrW   c                    s(   dt dtf fdd}tj||tjdS )z]A Micromamba base image. Micromamba allows for fast building of small Conda-based containers.r   rH   c                    s   t  | ddd}td| }d| }ddd| d	g}t|| |}| d
kr/|dd d i }| d
kr<tt|  i}t||dS )NFzImage.micromambarp   
micromambazmambaorg/micromamba:z-SHELL ["/usr/local/bin/_dockerfile_shell.sh"]zENV MAMBA_DOCKERFILE_ACTIVATE=1z)RUN micromamba install -n base -y python=z pip -c conda-forger>   CMD ["sleep", "  "]rF  )ro   rx   r  _registry_setup_commandsr   r   r   r   )r   validated_python_versionmicromamba_versiontagsetup_commandsr   r   rW   rL   rM   r    s    


z+_Image.micromamba.<locals>.build_dockerfiler8  r  rA  )r   r   r  r  r   DEPLOYMENT_NAMESPACE_GLOBALrW   r  r  rL   rX  rM   rO    s   z_Image.micromamba)	spec_filechannelsr  r  r9  r  r\  r]  c          	         sv   |pg }|rg |t |}tdd|sdu r| S dtdtf fdd}tjd| i|| jp4||t|d	S )
z7Install a list of additional packages using micromamba.micromamba_installr   Nr   rH   c           	         s   t }ddd  D }|rdnd}d u rdndtj }d u r*dn| d| d}d u r8g nd| d| g}d	g|d
| | | d}d u rVi n|tji}t||dS )NrV   c                 s   s    | ]}d | V  qdS )z -c NrL   )ru   channelrL   rL   rM   rw     r   zF_Image.micromamba_install.<locals>.build_dockerfile.<locals>.<genexpr>r   r   z-f z -n baser  r  zRUN micromamba install z --yesrF  )r   r   r   rW  r  r  r   )	r   r  channel_argsspaceremote_spec_filefile_argcopy_commandsr   r   r]  r  r\  rL   rM   r    s   
z3_Image.micromamba_install.<locals>.build_dockerfiler  r  )	r:   r  r   r   r   r  r  r  r5   )	rK   r\  r]  r  r  r9  r  r   r  rL   re  rM   r^    s   z_Image.micromamba_installrV  rX   rW  
add_pythonc                 C   s   g }|r.t ||ddd ddg}|dd }|dr"|d d	 }t|d
k r.|dd |dk r4dnd}g }|dkrW|dt dt dtd| d| t| g d|  kradkrkn n|	dt  d|  g|||S )NFT)rY   rZ   zCOPY /python/. /usr/localzSENV TERMINFO_DIRS=/etc/terminfo:/lib/terminfo:/usr/share/terminfo:/usr/lib/terminfor^   r   r]      z6RUN ln -s /usr/local/bin/python3 /usr/local/bin/pythonr>   z
python -m rV   r  r   z$RUN python -m pip install --upgrade package_toolsr	  r<   RUN rm zFROM )
ro   rh   rg   r
  insertr   r   rx   r   r   )rV  rX   rW  rf  add_python_commandspython_minorrequirements_prefixmodal_requirements_commandsrL   rL   rM   rS  4  s@   
z_Image._registry_setup_commands)setup_dockerfile_commandsr  rf  r   rp  c                   sh   dt t f fdd}d|vr|durttj||d< dtdtf fdd}tjd
|||d	|S )a<  Build a Modal Image from a public or private image registry, such as Docker Hub.

        The image must be built for the `linux/amd64` platform.

        If your image does not come with Python installed, you can use the `add_python` parameter
        to specify a version of Python to add to the image. Otherwise, the image is expected to
        have Python on PATH as `python`, along with `pip`.

        You may also use `setup_dockerfile_commands` to run Dockerfile commands before the
        remaining commands run. This might be useful if you want a custom Python installation or to
        set a `SHELL`. Prefer `run_commands()` when possible though.

        To authenticate against a private registry with static credentials, you must set the `secret` parameter to
        a `modal.Secret` containing a username (`REGISTRY_USERNAME`) and
        an access token or password (`REGISTRY_PASSWORD`).

        To authenticate against private registries with credentials from a cloud provider,
        use `Image.from_gcp_artifact_registry()` or `Image.from_aws_ecr()`.

        **Examples**

        ```python
        modal.Image.from_registry("python:3.11-slim-bookworm")
        modal.Image.from_registry("ubuntu:22.04", add_python="3.11")
        modal.Image.from_registry("nvcr.io/nvidia/pytorch:22.12-py3")
        ```
        rH   c                          rt jt tjdS d S N)rg  r6   	from_namer7   r   rZ  rL   rf  rL   rM   r>       z4_Image.from_registry.<locals>.context_mount_functionr=  Nr   c                    s6   t |  }i }| dkrtt|  i}t||dS )Nr>   rF  )r  rS  r   r   r   )r   r   r   rf  rp  rV  rL   rM   r    s
   z._Image.from_registry.<locals>.build_dockerfile)r8  r>  r  rL   )	r   r6   r   r   REGISTRY_AUTH_TYPE_STATIC_CREDSr   r   r  r  )rV  r   rp  r  rf  kwargsr>  r  rL   rw  rM   from_registryd  s   &
z_Image.from_registryc                K   8   d|v rt dttj|}tj| f||||d|S )a  Build a Modal image from a private image in Google Cloud Platform (GCP) Artifact Registry.

        You will need to pass a `modal.Secret` containing [your GCP service account key data](https://cloud.google.com/iam/docs/keys-create-delete#creating)
        as `SERVICE_ACCOUNT_JSON`. This can be done from the [Secrets](https://modal.com/secrets) page.
        Your service account should be granted a specific role depending on the GCP registry used:

        - For Artifact Registry images (`pkg.dev` domains) use
          the ["Artifact Registry Reader"](https://cloud.google.com/artifact-registry/docs/access-control#roles) role
        - For Container Registry images (`gcr.io` domains) use
          the ["Storage Object Viewer"](https://cloud.google.com/artifact-registry/docs/transition/setup-gcr-repo) role

        **Note:** This method does not use `GOOGLE_APPLICATION_CREDENTIALS` as that
        variable accepts a path to a JSON file, not the actual JSON string.

        See `Image.from_registry()` for information about the other parameters.

        **Example**

        ```python
        modal.Image.from_gcp_artifact_registry(
            "us-east1-docker.pkg.dev/my-project-1234/my-repo/my-image:my-version",
            secret=modal.Secret.from_name(
                "my-gcp-secret",
                required_keys=["SERVICE_ACCOUNT_JSON"],
            ),
            add_python="3.11",
        )
        ```
        r9  QPassing a list of 'secrets' is not supported; use the singular 'secret' argument.rp  r  rf  r=  )	TypeErrorr   r   REGISTRY_AUTH_TYPE_GCPr  rz  rV  r   rp  r  rf  ry  r=  rL   rL   rM   from_gcp_artifact_registry     'z!_Image.from_gcp_artifact_registryc                K   r{  )a  Build a Modal image from a private image in AWS Elastic Container Registry (ECR).

        You will need to pass a `modal.Secret` containing either IAM user credentials or OIDC
        configuration to access the target ECR registry.

        For IAM user authentication, set `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and `AWS_REGION`.

        For OIDC authentication, set `AWS_ROLE_ARN` and `AWS_REGION`.

        IAM configuration details can be found in the AWS documentation for
        ["Private repository policies"](https://docs.aws.amazon.com/AmazonECR/latest/userguide/repository-policies.html).

        For more details on using an AWS role to access ECR, see the [OIDC integration guide](https://modal.com/docs/guide/oidc-integration).

        See `Image.from_registry()` for information about the other parameters.

        **Example**

        ```python
        modal.Image.from_aws_ecr(
            "000000000000.dkr.ecr.us-east-1.amazonaws.com/my-private-registry:my-version",
            secret=modal.Secret.from_name(
                "aws",
                required_keys=["AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", "AWS_REGION"],
            ),
            add_python="3.11",
        )
        ```
        r9  r|  r}  )r~  r   r   REGISTRY_AUTH_TYPE_AWSr  rz  r  rL   rL   rM   from_aws_ecr  r  z_Image.from_aws_ecr)r  r   r  r9  r  rf  r?  r   rW  c                   s   |pg }|rg |t |}dtdtffdd}	t|}
tj|	t|t|d|
||d} fdd}dtdtf fd	d
}tjd|i|||dS )a  Build a Modal image from a local Dockerfile.

        If your Dockerfile does not have Python installed, you can use the `add_python` parameter
        to specify a version of Python to add to the image.

        **Usage:**

        ```python
        from modal import FilePatternMatcher

        # By default a .dockerignore file is used if present in the current working directory
        image = modal.Image.from_dockerfile(
            "./Dockerfile",
            add_python="3.12",
        )

        image = modal.Image.from_dockerfile(
            "./Dockerfile",
            add_python="3.12",
            ignore=["*.venv"],
        )

        image = modal.Image.from_dockerfile(
            "./Dockerfile",
            add_python="3.12",
            ignore=lambda p: p.is_relative_to(".venv"),
        )

        image = modal.Image.from_dockerfile(
            "./Dockerfile",
            add_python="3.12",
            ignore=FilePatternMatcher("**/*.txt"),
        )

        # When including files is simpler than excluding them, you can use the `~` operator to invert the matcher.
        image = modal.Image.from_dockerfile(
            "./Dockerfile",
            add_python="3.12",
            ignore=~FilePatternMatcher("**/*.py"),
        )

        # You can also read ignore patterns from a file.
        image = modal.Image.from_dockerfile(
            "./Dockerfile",
            add_python="3.12",
            ignore=FilePatternMatcher.from_file("/path/to/dockerignore"),
        )
        ```
        r   rH   c                    sJ   t tj }| d}W d    n1 sw   Y  t|i dS )N
rF  )r   r   rW  r  rm  rh   r   )r   r   r   rW  rL   rM   build_dockerfile_baseP  s   z5_Image.from_dockerfile.<locals>.build_dockerfile_base)r   r   r   )r8  r>  r:  r9  r?  c                      rq  rr  rs  rL   ru  rL   rM   add_python_mountd  rv  z0_Image.from_dockerfile.<locals>.add_python_mountc                    s:   t d| g  }i }| dkrt|  }t|i}t||dS )Nr  r>   rF  )r  rS  r   r   r   )r   r   r   requirements_pathru  rL   rM   build_dockerfile_pythonn  s   
z7_Image.from_dockerfile.<locals>.build_dockerfile_pythonr  )r7  r8  r>  r  )	r:   r  r   r   r5   r  r  r   r   )rW  r  r   r  r9  r  rf  r?  r   r  r:  r*  r  r  rL   )rf  rW  rM   from_dockerfile  s,   ?

z_Image.from_dockerfilec                    s:   t  tr	tddtdtf fdd}tj||tjdS )z<Default image, based on the official `python` Docker images.z>The `python_version` argument should be a string, not a float.r   rH   c                    s   i }| dkrt |  }t|i}t|  ddd}td| }d| d| g}| dkr5|dt d	t g |d
ddtd|  g | dkrR|dt|  g |dg d|   krbdkrln n|dt  | dkry|dd d t||dS )Nr>   FzImage.debian_slimrp   debianzFROM python:z-slim-r  r   RUN apt-get updatez3RUN apt-get install -y gcc gfortran build-essentialzRUN pip install --upgrade ri  r	  zRRUN echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selectionsr<   rj  rP  rQ  rR  rF  )r   r   r   rx   r   r   r   r   )r   r   r  full_python_versiondebian_codenamer   rX  rL   rM   r    sF   

z,_Image.debian_slim.<locals>.build_dockerfilerY  )	rc   floatr~  r   r   r  r  r   rZ  r[  rL   rX  rM   debian_slim}  s   
.z_Image.debian_slim)r  r  r9  r  c                   st   t dd|}|s
| S t| dtdtf fdd}|pg }|r)g |t|}tjd| i|| j	p3|t
||dS )	zInstall a list of Debian packages using `apt`.

        **Example**

        ```python
        image = modal.Image.debian_slim().apt_install("git")
        ```
        apt_installr   r   rH   c                    s   ddd  g}t |i dS )Nr  r  zRUN apt-get install -y rF  r  r  r  rL   rM   r    s
   z,_Image.apt_install.<locals>.build_dockerfiler  r  )r   r   r   r   r   r:   r  r  r  r  r5   )rK   r  r  r9  r  r   r  r  rL   r  rM   r    s   
z_Image.apt_installi  rL   )r  r9  rM  network_file_systemsr  cpumemoryr   cloudregionr  r   ry  include_sourceraw_f.r  r  r  r   r  r  r   ry  r  c                C   s  |pg }|rg |t |}ddlm} t|s$tdt|j d|jdkr-tdt|}|j	|d| |||||
|||	|d|d	}t
|t
| d
krst }t||f|}t
|tkrktdt
| dt dtj||d}nd}tjd| i||| jp|dS )al  Run user-defined function `raw_f` as an image build step.

        The function runs like an ordinary Modal Function, accepting a resource configuration and integrating
        with Modal features like Secrets and Volumes. Unlike ordinary Modal Functions, any changes to the
        filesystem state will be captured on container exit and saved as a new Image.

        **Note**

        Only the source code of `raw_f`, the contents of `**kwargs`, and any referenced *global* variables
        are used to determine whether the image has changed and needs to be rebuilt.
        If this function references other functions or variables, the image will not be rebuilt if you
        make changes to them. You can force a rebuild by changing the function's source code itself.

        **Example**

        ```python notest

        def my_build_function():
            open("model.pt", "w").write("parameters!")

        image = (
            modal.Image
                .debian_slim()
                .pip_install("torch")
                .run_function(my_build_function, secrets=[...], mounts=[...])
        )
        ```
        r   )	_Functionz7Argument to Image.run_function must be a function, not r^   z<lambda>z5Image.run_function does not support lambda functions.NT)r  rI  r9  r  rM  r  r  r  r  r   r  is_builder_functionr  r   z+Arguments to `run_function` are too large (z bytes). Maximum size is z bytes.)r   data_formatr  )r7  r;  r<  r  )r:   r  
_functionsr  callabler,   rd   rI   r"   
from_localri   r   r   r   r   FunctionInputr  r  r  )rK   r  r  r9  rM  r  r  r  r  r   r  r  r  r   ry  r  r  infofunctionr  args_serializedr<  rL   rL   rM   run_function  sZ   0
z_Image.run_functionvarsc                    sL   dd    D }|rtd| dtdtf fdd}tjd| i|d	S )
zSets the environment variables in an Image.

        **Example**

        ```python
        image = (
            modal.Image.debian_slim()
            .env({"HF_HUB_ENABLE_HF_TRANSFER": "1"})
        )
        ```
        c                 S   s   g | ]\}}t |ts|qS rL   r   ru   keyvalrL   rL   rM   rJ  R	  s    z_Image.env.<locals>.<listcomp>z3Image ENV variables must be strings. Invalid keys: r   rH   c                    s$   dd    D }tdg| i dS )Nc                 S   s&   g | ]\}}d | dt | qS )zENV =r   r  rL   rL   rM   rJ  W	  s   & z8_Image.env.<locals>.build_dockerfile.<locals>.<listcomp>r  rF  )rk  r   )r   env_commandsr  rL   rM   r  V	  s   z$_Image.env.<locals>.build_dockerfiler  r7  r8  )rk  r,   r   r   r  r  )rK   r  non_str_keysr  rL   r  rM   r  F	  s   z
_Image.envc                    s(   dt dtf fdd}tjd| i|dS )aO  Set the working directory for subsequent image build steps and function execution.

        **Example**

        ```python
        image = (
            modal.Image.debian_slim()
            .run_commands("git clone https://xyz app")
            .workdir("/app")
            .run_commands("yarn install")
        )
        ```
        r   rH   c                    s$   ddt t  g}t|i dS )Nr  zWORKDIR rF  )r   r   rT   r   r  r  rL   rM   r  n	  s   z(_Image.workdir.<locals>.build_dockerfiler  r  )r   r   r  r  )rK   rW  r  rL   r  rM   workdir_	  s
   z_Image.workdirr  c                 C   s`   t |trtdd |D stdtdd|}|r#dd| d nd}d| d	}| |S )
a#  Set the default command (`CMD`) to run when a container is started.

        Used with `modal.Sandbox`. Has no effect on `modal.Function`.

        **Example**

        ```python
        image = (
            modal.Image.debian_slim().cmd(["python", "app.py"])
        )
        ```
        c                 s   r   r   r   rB  rL   rL   rM   rw   	  r   z_Image.cmd.<locals>.<genexpr>z$Image CMD must be a list of strings.r  rD  rE  rV   zCMD [rF  rG  )rK   r  cmd_strrI  rL   rL   rM   r  w	  s   
z
_Image.cmdc              
   c   s    t d}zdV  W dS  tyE } z-| js| j| n|| jkr$ t|ts:t	
dt|  W Y d}~dS W Y d}~dS d}~ww )a\  
        Used to import packages in global scope that are only available when running remotely.
        By using this context manager you can avoid an `ImportError` due to not having certain
        packages installed locally.

        **Usage:**

        ```python notest
        with image.imports():
            import torch
        ```
        r   NzEWarning: caught a non-ImportError exception in an `imports()` block: )r&   r   rq  is_hydratedr  r   r   rc   ImportErrorwarningswarnrepr)rK   r  r  rL   rL   rM   imports	  s   


"z_Image.importsc                 C  sr   d}t j| jd|dd}| jjj|2 z 3 dH W }|jjr" dS |j	r(|j	}|j
D ]	}|jr4|jV  q+q6 dS )zStreams logs from an image, or returns logs from an already completed image.

        This method is considered private since its interface may change - use it at your own risk!
        rV   r   T)r   r   r   include_logs_for_finishedN)r   r   r   r   r   r   r   r   r   r   r   r   )rK   r   r  r  r  rL   rL   rM   _logs	  s    

z_Image._logsc                    s   | j std| S )r   zeImages cannot currently be hydrated on demand; you can build an Image by running an App that uses it.)r  r*   )rK   r   rL   rL   rM   hydrate	  s   z_Image.hydrate)r  r  )F)r^   r   )r  r  rH   r  )r#  )NF)]rI   rR   rS   r   rU   r   r   rq  r  r6   r   rT   r  r   r   r  r  r  r   r  r  r4  propertyr  r5  r6  staticmethodDEPLOYMENT_NAMESPACE_WORKSPACEry   r	   r   r   r   r:   r  r  r   rs   r;   r  r   r   r0  r  r  r1   r  r   classmethodr  r   r  r  r4   r  r  r  r  r  r"  r=  r   r[  rC  rL  r   rN  rO  r^  rS  rz  r  r  r  r  r  r   r%   r8   r  r
  r  r  r  r  
contextlibcontextmanagerr  r   AsyncGeneratorr  r$   r  rL   rL   rL   rM   r    s  
 

	

  ^(!
	

H
,"
@	


J	


m	


0	


F
	


w


a

	


 ,

	

J



%	


0/@22


	
q<

.

	


e
r  im)type_prefix)TFrV   )NFrV   r   )NNNFrV   )r  r   r   re   r   ra   r  r  collections.abcr   r   dataclassesr   inspectr   pathlibr   r   r   r	   r
   r   r   r   r   r  google.protobuf.messager   grpclib.exceptionsr   r   modal._serializationr   modal_protor   _load_contextr   _objectr   r   	_resolverr   _serializationr   r   _utils.async_utilsr   r   r   r   _utils.blob_utilsr   _utils.docker_utilsr    r!   _utils.function_utilsr"   _utils.mount_utilsr#   r   r$   cloud_bucket_mountr%   r&   r'   r(   environmentsr)   r|  r*   r+   r,   r-   r.   r/   r0   file_pattern_matcherr1   r2   r3   r  r4   r5   r  r6   r7   network_file_systemr8   outputr9   r   r:   rX  r;   TYPE_CHECKINGmodal._functionsr0  modal.clientr   rE   ry   r   rT   r   __file__r  r   r   rG   r    COPY_DEPRECATION_MESSAGE_PATTERNrU   ro   r   rx   r   r   r   r   r   r   r   r   r   r   ImageJoinStreamingResponser  r  ru  rL   rL   rL   rM   <module>   s0  
$
$	
'
.


&#                E