o
    ;i&^                  	   @   s  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	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 ddlmZmZmZmZmZ ddlmZ ddlm Z m!Z! ddl"m#Z#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. ddl/m0Z0 ddl1m2Z2m3Z3m4Z4m5Z5m6Z6m7Z7 G dd dZ8e8 Z9dd Z:ddde;defdd Z<e9fddde;d!edefd"d#Z=eG d$d% d%Z>G d&d' d'Z?e$e?Z@G d(d ded)d*ZAe$eAZBdS )+    N)AsyncIteratorMapping)	dataclass)datetime)AnyOptionalUnion)Message)classproperty)asynccontextmanager)Retry)api_pb2   )LoadContext) EPHEMERAL_OBJECT_HEARTBEAT_SLEEP_get_environment_name_Objectlive_methodlive_method_gen)Resolver)deserialize	serialize)TaskContextsynchronize_api)deprecation_warningwarn_if_passing_namespace)check_object_name)as_timestamptimestamp_to_localized_dt)_Client)logger)AlreadyExistsErrorDeserializationErrorErrorInvalidErrorNotFoundErrorRequestSizeErrorc                   @   s   e Zd ZdefddZdS )_NoDefaultSentinelreturnc                 C   s   dS )Nz... selfr)   r)   >/home/ubuntu/.local/lib/python3.10/site-packages/modal/dict.py__repr__*   s   z_NoDefaultSentinel.__repr__N)__name__
__module____qualname__strr-   r)   r)   r)   r,   r'   )   s    r'   c                 C   s   dd |   D S )Nc                 S   s&   g | ]\}}t jt|t|d qS ))keyvalue)r   	DictEntryr   ).0kvr)   r)   r,   
<listcomp>2   s   & z#_serialize_dict.<locals>.<listcomp>)items)datar)   r)   r,   _serialize_dict1   s   r;   dict_Dictr:   r(   c              
   C   s^   zt || jW S  ty. } z| jrd| j dnd| j }td| d| |d }~ww )NDict ''ephemeral Dict z!Failed to deserialize a key from : )r   _clientr"   name	object_id)r<   r:   excdict_identifierr)   r)   r,   _deserialize_dict_key5   s    rG   r2   c              
   C   sz   zt || jW S  ty< } z)|tu rdnd|}| jr$d| j dnd| j }td| d| d| |d }~ww )	N z	 for key r>   r?   r@   zFailed to deserialize valuez from rA   )r   rB   r"   _NO_DEFAULTrC   rD   )r<   r:   r2   rE   key_identifierrF   r)   r)   r,   _deserialize_dict_value=   s    rK   c                   @   s2   e Zd ZU dZee ed< eed< ee ed< dS )DictInfoz Information about a Dict object.rC   
created_at
created_byN)r.   r/   r0   __doc__r   r1   __annotations__r   r)   r)   r)   r,   rL   H   s
   
 rL   c                   @   s   e Zd ZdZedddddededee dee d	df
d
dZ	eddddddee
 deeeef  dedee d	ejd f
ddZedddddededee dee fddZdS )_DictManagerz7Namespace with methods for managing named Dict objects.FN)allow_existingenvironment_nameclientrC   rR   rS   rT   r(   c                   s~   t | d |du rt I dH n|}|rtjntj}tj| t||d}z|j	|I dH  W dS  t
y>   |s; Y dS w )a  Create a new Dict object.

        **Examples:**

        ```python notest
        modal.Dict.objects.create("my-dict")
        ```

        Dicts will be created in the active environment, or another one can be specified:

        ```python notest
        modal.Dict.objects.create("my-dict", environment_name="dev")
        ```

        By default, an error will be raised if the Dict already exists, but passing
        `allow_existing=True` will make the creation attempt a no-op in this case.

        ```python notest
        modal.Dict.objects.create("my-dict", allow_existing=True)
        ```

        Note that this method does not return a local instance of the Dict. You can use
        `modal.Dict.from_name` to perform a lookup after creation.

        Added in v1.1.2.

        DictN)deployment_namerS   object_creation_type)r   r   from_envr   &OBJECT_CREATION_TYPE_CREATE_IF_MISSING*OBJECT_CREATION_TYPE_CREATE_FAIL_IF_EXISTSDictGetOrCreateRequestr   stubDictGetOrCreater!   )rC   rR   rS   rT   rW   reqr)   r)   r,   createW   s&   
#z_DictManager.createrH   )max_objectscreated_beforerS   rT   r`   ra   r=   c                    s    du rt  I dH n  durdk rtdg dtdtf fdd}|t|I dH }	 |r7n|d	 jjjI dH }q4 fd
dD }durX|d S |S )a  Return a list of hydrated Dict objects.

        **Examples:**

        ```python
        dicts = modal.Dict.objects.list()
        print([d.name for d in dicts])
        ```

        Dicts will be retreived from the active environment, or another one can be specified:

        ```python notest
        dev_dicts = modal.Dict.objects.list(environment_name="dev")
        ```

        By default, all named Dict are returned, newest to oldest. It's also possible to limit the
        number of results and to filter by creation date:

        ```python
        dicts = modal.Dict.objects.list(max_objects=10, created_before="2025-01-01")
        ```

        Added in v1.1.2.

        Nr   zmax_objects cannot be negativera   r(   c                    s   d u rdnt dt }tj|| d}tjt|d} j|I d H }|j	 t|j	|k p?d uo?tk}|S )Nd   )r`   ra   )rS   
pagination)
minlenr   ListPaginationDictListRequestr   r\   DictListextenddicts)ra   max_page_sizerc   r^   respfinishedrT   rS   r9   r`   r)   r,   retrieve_page   s   "z(_DictManager.list.<locals>.retrieve_pageTc                    s.   g | ]}t j|j |jd t |jdqS )Tis_another_apprep)r=   _new_hydrateddict_idmetadata_reprrC   )r5   itemrT   rS   r)   r,   r8      s    z%_DictManager.list.<locals>.<listcomp>)	r   rX   r$   floatboolr   rv   creation_inforM   )r`   ra   rS   rT   ro   rm   rj   r)   rn   r,   list   s    !
z_DictManager.list)allow_missingrS   rT   r~   c                   sb   zt j| |d|I dH }W n ty   |s Y dS w tj|jd}|jj	|I dH  dS )a  Delete a named Dict.

        Warning: This deletes an *entire Dict*, not just a specific key.
        Deletion is irreversible and will affect any Apps currently using the Dict.

        **Examples:**

        ```python notest
        await modal.Dict.objects.delete("my-dict")
        ```

        Dicts will be deleted from the active environment, or another one can be specified:

        ```python notest
        await modal.Dict.objects.delete("my-dict", environment_name="dev")
        ```

        Added in v1.1.2.

        )rS   Nru   )
r=   	from_namehydrater%   r   DictDeleteRequestrD   rB   r\   
DictDelete)rC   r~   rS   rT   objr^   r)   r)   r,   delete   s   z_DictManager.delete)r.   r/   r0   rO   staticmethodr1   r{   r   r   r_   intr   r   builtinsr}   r   r)   r)   r)   r,   rQ   T   s\    4CrQ   c                   @   s  e Zd ZU dZdZee ed< dZee	j
 ed< i fddZedefdd	Zedee fd
dZdee fddZde	j
fddZeedddefded  dee dee dee deded  fddZe	dHddddddedee dee dedee dd fddZe	dHdedee dd fdd Z eddd!dedee dee fd"d#Z!e"de#fd$d%Z$e"dId&d'Z%e"dHd(e&d)ee& de&fd*d+Z'e"d(e&defd,d-Z(e"de)fd.d/Z*e"d(e&de&fd0d1Z+e"dHd2ee, ddfd3d4Z-e"dd5d(e&d6e&d7edefd8d9Z.e"d(e&d6e&ddfd:d;Z/e"e0fd(e&d)e&de&fd<d=Z1e"d(e&de&fd>d?Z2e"d(e&defd@dAZ3e4dee& fdBdCZ5e4dee& fdDdEZ6e4dee7e&e&f  fdFdGZ8dS )Jr=   a  Distributed dictionary for storage in Modal apps.

    Dict contents can be essentially any object so long as they can be serialized by
    `cloudpickle`. This includes other Modal objects. If writing and reading in different
    environments (eg., writing locally and reading remotely), it's necessary to have the
    library defining the data type installed, with compatible versions, on both sides.
    Additionally, cloudpickle serialization is not guaranteed to be deterministic, so it is
    generally recommended to use primitive types for keys.

    **Lifetime of a Dict and its items**

    An individual Dict entry will expire after 7 days of inactivity (no reads or writes). The
    Dict entries are written to durable storage.

    Legacy Dicts (created before 2025-05-20) will still have entries expire 30 days after being
    last added. Additionally, contents are stored in memory on the Modal server and could be lost
    due to unexpected server restarts. Eventually, these Dicts will be fully sunset.

    **Usage**

    ```python
    from modal import Dict

    my_dict = Dict.from_name("my-persisted_dict", create_if_missing=True)

    my_dict["some key"] = "some value"
    my_dict[123] = 456

    assert my_dict["some key"] == "some value"
    assert my_dict[123] == 456
    ```

    The `Dict` class offers a few methods for operations that are usually accomplished
    in Python with operators, such as `Dict.put` and `Dict.contains`. The advantage of
    these methods is that they can be safely called in an asynchronous context by using
    the `.aio` suffix on the method, whereas their operator-based analogues will always
    run synchronously and block the event loop.

    For more examples, see the [guide](https://modal.com/docs/guide/dicts-and-queues#modal-dicts).
    N_name	_metadatac                 C   s   t d)zmdmd:hiddenz_`Dict(...)` constructor is not allowed. Please use `Dict.from_name` or `Dict.ephemeral` instead)RuntimeError)r+   r:   r)   r)   r,   __init__&  s   z_Dict.__init__r(   c                 C   s   t S N)rQ   )clsr)   r)   r,   objects,  s   z_Dict.objectsc                 C   s   | j S r   )r   r*   r)   r)   r,   rC   0  s   z
_Dict.namerv   c                 C   s*   |rt |tjs
J || _|j| _d S d S r   )
isinstancer   DictMetadatar   rC   r   )r+   rv   r)   r)   r,   _hydrate_metadata4  s
   z_Dict._hydrate_metadatac                 C   s   | j sJ | j S r   )r   r*   r)   r)   r,   _get_metadata:  s   
z_Dict._get_metadatar   r:   rT   rS   _heartbeat_sleepc              	     s    du rt  I dH  |rtdd t|dur|ni }tjtjt||d jj	t
dddI dH }t 4 I dH ,}tj|jd|j fd	d
|d | j|j |jdddV  W d  I dH  dS 1 I dH sow   Y  dS )aH  Creates a new ephemeral Dict within a context manager:

        Usage:
        ```python
        from modal import Dict

        with Dict.ephemeral() as d:
            d["foo"] = "bar"
        ```

        ```python notest
        async with Dict.ephemeral() as d:
            await d.put.aio("foo", "bar")
        ```
        N        z_Passing data to `modal.Dict.ephemeral` is deprecated and will stop working in a future release.)rW   rS   r:   g      $@)total_timeout)retryr   c                      s    j S r   )r\   DictHeartbeatr)   rT   requestr)   r,   <lambda>f  s    z!_Dict.ephemeral.<locals>.<lambda>)sleepTzmodal.Dict.ephemeral()rq   )r   rX   r   r;   r   r[   OBJECT_CREATION_TYPE_EPHEMERALr   r\   r]   r   r   DictHeartbeatRequestru   infinite_looprt   rv   )r   r:   rT   rS   r   
serializedresponsetcr)   r   r,   	ephemeral>  s4   
.z_Dict.ephemeralF)	namespacerS   create_if_missingrT   rC   r   c             
      sr   t d t|d rtdd dtdtdtdtt f fd	d
}t|}tj	||ddt||ddS )aP  Reference a named Dict, creating if necessary.

        This is a lazy method that defers hydrating the local
        object with metadata from Modal servers until the first
        time it is actually used.

        ```python
        d = modal.Dict.from_name("my-dict", create_if_missing=True)
        d[123] = 456
        ```
        rU   zmodal.Dict.from_namer   z_Passing data to `modal.Dict.from_name` is deprecated and will stop working in a future release.r+   resolverload_contextexisting_object_idc                    sr   t d urni }tj|j rtjnd |d}|jj|I d H }t	d|j
  | |j
|j|j d S )N)rV   rS   rW   r:   zCreated dict with id )r;   r   r[   rS   rY   rT   r\   r]   r    debugru   _hydraterv   )r+   r   r   r   r   r^   r   r   r:   rC   r)   r,   _load  s   z_Dict.from_name.<locals>._loadTrS   rT   )rr   hydrate_lazilyrC   load_context_overrides)
r   r   r   r=   r   r   r   r1   rw   _from_loader)rC   r:   r   rS   r   rT   r   rs   r)   r   r,   r   o  s"   

&
z_Dict.from_nameru   c              	      sH   dt dtdtdtt f fdd}d d}t j||d	d	t|d
dS )a  Construct a Dict from an id and look up the Dict metadata.

        This is a lazy method that defers hydrating the local
        object with metadata from Modal servers until the first
        time it is actually used.

        The ID of a Dict object can be accessed using `.object_id`.

        **Example:**

        ```python notest
        @app.function()
        def my_worker(dict_id: str):
            d = modal.Dict.from_id(dict_id)
            d["key"] = "Hello from remote function!"

        with modal.Dict.ephemeral() as d:
            # Pass the dict ID to a remote function
            my_worker.remote(d.object_id)
            print(d["key"])  # "Hello from remote function!"
        ```
        r+   r   r   r   c                    s:   t j d}|jj|I d H }| |j|j|j d S )Nr   )r   DictGetByIdRequestrT   r\   DictGetByIdr   ru   rv   )r+   r   r   r   r^   r   r   r)   r,   r     s   z_Dict.from_id.<locals>._loadzDict.from_id()T)rT   )rr   r   r   )r=   r   r   r   r1   r   )ru   rT   r   rs   r)   r   r,   from_id  s   "z_Dict.from_idry   c                   s(   t dd tjj| ||dI dH  dS )a>  mdmd:hidden
        Delete a named Dict object.

        Warning: This deletes an *entire Dict*, not just a specific key.
        Deletion is irreversible and will affect any Apps currently using the Dict.

        DEPRECATED: This method is deprecated; we recommend using `modal.Dict.objects.delete` instead.
        )r      r   zZ`modal.Dict.delete` is deprecated; we recommend using `modal.Dict.objects.delete` instead.r   N)r   r=   r   r   )rC   rT   rS   r)   r)   r,   r     s
   z_Dict.deletec                    s0   |   }|j}t|jpdt|j|jpddS )z)Return information about the Dict object.N)rC   rM   rN   )r   r|   rL   rC   r   rM   rN   )r+   rv   r|   r)   r)   r,   info  s   z
_Dict.infoc                    s(   t j| jd}| jj|I dH  dS )zRemove all items from the Dict.r   N)r   DictClearRequestrD   rB   r\   	DictClear)r+   r^   r)   r)   r,   clear  s   z_Dict.clearr2   defaultc                    sB   t j| jt|d}| jj|I dH }|js|S t| |j	|S )z_Get the value associated with a key.

        Returns `default` if key does not exist.
        ru   r2   N)
r   DictGetRequestrD   r   rB   r\   DictGetfoundrK   r3   r+   r2   r   r^   rl   r)   r)   r,   get  s   z	_Dict.getc                    s0   t j| jt|d}| jj|I dH }|jS )zReturn if a key is present.r   N)r   DictContainsRequestrD   r   rB   r\   DictContainsr   )r+   r2   r^   rl   r)   r)   r,   contains  s   z_Dict.containsc                    s*   t j| jd}| jj|I dH }|jS )zvReturn the length of the Dict.

        Note: This is an expensive operation and will return at most 100,000.
        r   N)r   DictLenRequestrD   rB   r\   DictLenre   r+   r^   rl   r)   r)   r,   re     s   z	_Dict.lenc                    s:   t  }| ||I dH }||u rt| d| j |S )zGet the value associated with a key.

        Note: this function will block the event loop when called in an async context.
        N not in dict )objectr   KeyErrorrD   )r+   r2   	NOT_FOUNDr3   r)   r)   r,   __getitem__  s   z_Dict.__getitem__otherc             
      s   i } r|  fdd  D  |r| | t|}tj| j|d}z| jj|I dH  W dS  t	yL } zdt
|v rFtd||d}~ww )z&Update the Dict with additional items.c                    s   i | ]}| | qS r)   r)   )r5   r6   r   r)   r,   
<dictcomp>#  s    z _Dict.update.<locals>.<dictcomp>)ru   updatesNstatus = '413'z Dict.update request is too large)updatekeysr;   r   DictUpdateRequestrD   rB   r\   
DictUpdater#   r1   r&   )r+   r   kwargscontentsr   r^   rE   r)   r   r,   r     s    

z_Dict.update)skip_if_existsr3   r   c          	   
      st   ||i}t |}tj| j||d}z| jj|I dH }|jW S  ty9 } zdt	|v r3t
d||d}~ww )zAdd a specific key-value pair to the Dict.

        Returns True if the key-value pair was added and False if it wasn't because the key already existed and
        `skip_if_exists` was set.
        )ru   r   if_not_existsNr   zDict.put request is too large)r;   r   r   rD   rB   r\   r   createdr#   r1   r&   )	r+   r2   r3   r   r   r   r^   rl   rE   r)   r)   r,   put0  s   
z	_Dict.putc                    s   |  ||I dH S )zSet a specific key-value pair to the Dict.

        Note: this function will block the event loop when called in an async context.
        N)r   )r+   r2   r3   r)   r)   r,   __setitem__C  s   z_Dict.__setitem__c                    s^   t j| jt|d}| jj|I dH }|js(|tur|S t	| d| j t
| |j|S )zRemove a key from the Dict, returning the value if it exists.

        If key is not found, return default if provided, otherwise raise KeyError.
        r   Nr   )r   DictPopRequestrD   r   rB   r\   DictPopr   rI   r   rK   r3   r   r)   r)   r,   popK  s   z	_Dict.popc                       |  |I dH S )z|Delete a key from the Dict.

        Note: this function will block the event loop when called in an async context.
        N)r   r+   r2   r)   r)   r,   __delitem__Y     z_Dict.__delitem__c                    r   )z|Return if a key is present.

        Note: this function will block the event loop when called in an async context.
        N)r   r   r)   r)   r,   __contains__a  r   z_Dict.__contains__c                 C  sD   t j| jdd}| jjj|2 z3 dH W }t| |jV  q6 dS )zReturn an iterator over the keys in this Dict.

        Note that (unlike with Python dicts) the return value is a simple iterator,
        and results are unordered.
        T)ru   r   N)	r   DictContentsRequestrD   rB   r\   DictContentsunary_streamrG   r2   r   r)   r)   r,   r   i  s
   z
_Dict.keysc              	   C  sn   t j| jdd}| jjj|2 z"3 dH W }zt| |j}W n t	y*   t
}Y nw t| |j|V  q6 dS )zReturn an iterator over the values in this Dict.

        Note that (unlike with Python dicts) the return value is a simple iterator,
        and results are unordered.
        T)ru   valuesN)r   r   rD   rB   r\   r   r   rG   r2   r"   rI   rK   r3   )r+   r^   rl   	key_deserr)   r)   r,   r   t  s   z_Dict.valuesc                 C  s\   t j| jddd}| jjj|2 z3 dH W }t| |j}t	| |j
|}||fV  q6 dS )zReturn an iterator over the (key, value) tuples in this Dict.

        Note that (unlike with Python dicts) the return value is a simple iterator,
        and results are unordered.
        T)ru   r   r   N)r   r   rD   rB   r\   r   r   rG   r2   rK   r3   )r+   r^   rl   r   value_deserr)   r)   r,   r9     s   z_Dict.itemsr   )r(   N)9r.   r/   r0   rO   r   r   r1   rP   r   r   r   r   r
   rQ   r   propertyrC   r	   r   r   classmethodr   r   typer<   r   rz   r   r   r   r{   r   r   r   r   rL   r   r   r   r   r   r   re   r   r   r   r   r   rI   r   r   r   r   r   r   tupler9   r)   r)   r)   r,   r=      s   
 )/3)
	"
 di)type_prefix)Cr   collections.abcr   r   dataclassesr   r   typingr   r   r   google.protobuf.messager	   synchronicityr
   synchronicity.async_wrapr   modal._utils.grpc_utilsr   modal_protor   _load_contextr   _objectr   r   r   r   r   	_resolverr   _serializationr   r   _utils.async_utilsr   r   _utils.deprecationr   r   _utils.name_utilsr   _utils.time_utilsr   r   rT   r   configr    	exceptionr!   r"   r#   r$   r%   r&   r'   rI   r;   bytesrG   rK   rL   rQ   DictManagerr=   rU   r)   r)   r)   r,   <module>   sH    
 #   