modal 1.1.1.dev41__py3-none-any.whl → 1.1.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of modal might be problematic. Click here for more details.
- modal/__main__.py +1 -2
- modal/_container_entrypoint.py +18 -7
- modal/_functions.py +135 -13
- modal/_object.py +13 -2
- modal/_partial_function.py +8 -8
- modal/_runtime/asgi.py +3 -2
- modal/_runtime/container_io_manager.py +20 -14
- modal/_runtime/container_io_manager.pyi +38 -13
- modal/_runtime/execution_context.py +18 -2
- modal/_runtime/execution_context.pyi +4 -1
- modal/_runtime/gpu_memory_snapshot.py +158 -54
- modal/_utils/blob_utils.py +83 -24
- modal/_utils/function_utils.py +4 -3
- modal/_utils/time_utils.py +28 -4
- modal/app.py +8 -4
- modal/app.pyi +8 -8
- modal/cli/dict.py +14 -11
- modal/cli/entry_point.py +9 -3
- modal/cli/launch.py +102 -4
- modal/cli/profile.py +1 -0
- modal/cli/programs/launch_instance_ssh.py +94 -0
- modal/cli/programs/run_marimo.py +95 -0
- modal/cli/queues.py +49 -19
- modal/cli/secret.py +45 -18
- modal/cli/volume.py +14 -16
- modal/client.pyi +2 -10
- modal/cls.py +12 -2
- modal/cls.pyi +9 -1
- modal/config.py +7 -7
- modal/dict.py +206 -12
- modal/dict.pyi +358 -4
- modal/experimental/__init__.py +130 -0
- modal/file_io.py +1 -1
- modal/file_io.pyi +2 -2
- modal/file_pattern_matcher.py +25 -16
- modal/functions.pyi +111 -11
- modal/image.py +9 -3
- modal/image.pyi +7 -7
- modal/mount.py +20 -13
- modal/mount.pyi +16 -3
- modal/network_file_system.py +8 -2
- modal/object.pyi +3 -0
- modal/parallel_map.py +346 -101
- modal/parallel_map.pyi +108 -0
- modal/proxy.py +2 -1
- modal/queue.py +199 -9
- modal/queue.pyi +357 -3
- modal/sandbox.py +6 -5
- modal/sandbox.pyi +17 -14
- modal/secret.py +196 -3
- modal/secret.pyi +372 -0
- modal/volume.py +239 -23
- modal/volume.pyi +405 -10
- {modal-1.1.1.dev41.dist-info → modal-1.1.2.dist-info}/METADATA +2 -2
- {modal-1.1.1.dev41.dist-info → modal-1.1.2.dist-info}/RECORD +68 -66
- modal_docs/mdmd/mdmd.py +11 -1
- modal_proto/api.proto +37 -10
- modal_proto/api_grpc.py +32 -0
- modal_proto/api_pb2.py +627 -597
- modal_proto/api_pb2.pyi +107 -19
- modal_proto/api_pb2_grpc.py +67 -2
- modal_proto/api_pb2_grpc.pyi +24 -8
- modal_proto/modal_api_grpc.py +2 -0
- modal_version/__init__.py +1 -1
- {modal-1.1.1.dev41.dist-info → modal-1.1.2.dist-info}/WHEEL +0 -0
- {modal-1.1.1.dev41.dist-info → modal-1.1.2.dist-info}/entry_points.txt +0 -0
- {modal-1.1.1.dev41.dist-info → modal-1.1.2.dist-info}/licenses/LICENSE +0 -0
- {modal-1.1.1.dev41.dist-info → modal-1.1.2.dist-info}/top_level.txt +0 -0
modal/dict.py
CHANGED
|
@@ -2,25 +2,32 @@
|
|
|
2
2
|
from collections.abc import AsyncIterator, Mapping
|
|
3
3
|
from dataclasses import dataclass
|
|
4
4
|
from datetime import datetime
|
|
5
|
-
from typing import Any, Optional
|
|
5
|
+
from typing import Any, Optional, Union
|
|
6
6
|
|
|
7
7
|
from google.protobuf.message import Message
|
|
8
|
-
from grpclib import GRPCError
|
|
8
|
+
from grpclib import GRPCError, Status
|
|
9
|
+
from synchronicity import classproperty
|
|
9
10
|
from synchronicity.async_wrap import asynccontextmanager
|
|
10
11
|
|
|
11
12
|
from modal_proto import api_pb2
|
|
12
13
|
|
|
13
|
-
from ._object import
|
|
14
|
+
from ._object import (
|
|
15
|
+
EPHEMERAL_OBJECT_HEARTBEAT_SLEEP,
|
|
16
|
+
_get_environment_name,
|
|
17
|
+
_Object,
|
|
18
|
+
live_method,
|
|
19
|
+
live_method_gen,
|
|
20
|
+
)
|
|
14
21
|
from ._resolver import Resolver
|
|
15
22
|
from ._serialization import deserialize, serialize
|
|
16
23
|
from ._utils.async_utils import TaskContext, synchronize_api
|
|
17
24
|
from ._utils.deprecation import deprecation_warning, warn_if_passing_namespace
|
|
18
25
|
from ._utils.grpc_utils import retry_transient_errors
|
|
19
26
|
from ._utils.name_utils import check_object_name
|
|
20
|
-
from ._utils.time_utils import timestamp_to_localized_dt
|
|
27
|
+
from ._utils.time_utils import as_timestamp, timestamp_to_localized_dt
|
|
21
28
|
from .client import _Client
|
|
22
29
|
from .config import logger
|
|
23
|
-
from .exception import RequestSizeError
|
|
30
|
+
from .exception import AlreadyExistsError, InvalidError, NotFoundError, RequestSizeError
|
|
24
31
|
|
|
25
32
|
|
|
26
33
|
def _serialize_dict(data):
|
|
@@ -29,7 +36,7 @@ def _serialize_dict(data):
|
|
|
29
36
|
|
|
30
37
|
@dataclass
|
|
31
38
|
class DictInfo:
|
|
32
|
-
"""Information about
|
|
39
|
+
"""Information about a Dict object."""
|
|
33
40
|
|
|
34
41
|
# This dataclass should be limited to information that is unchanging over the lifetime of the Dict,
|
|
35
42
|
# since it is transmitted from the server when the object is hydrated and could be stale when accessed.
|
|
@@ -39,6 +46,173 @@ class DictInfo:
|
|
|
39
46
|
created_by: Optional[str]
|
|
40
47
|
|
|
41
48
|
|
|
49
|
+
class _DictManager:
|
|
50
|
+
"""Namespace with methods for managing named Dict objects."""
|
|
51
|
+
|
|
52
|
+
@staticmethod
|
|
53
|
+
async def create(
|
|
54
|
+
name: str, # Name to use for the new Dict
|
|
55
|
+
*,
|
|
56
|
+
allow_existing: bool = False, # If True, no-op when the Dict already exists
|
|
57
|
+
environment_name: Optional[str] = None, # Uses active environment if not specified
|
|
58
|
+
client: Optional[_Client] = None, # Optional client with Modal credentials
|
|
59
|
+
) -> None:
|
|
60
|
+
"""Create a new Dict object.
|
|
61
|
+
|
|
62
|
+
**Examples:**
|
|
63
|
+
|
|
64
|
+
```python notest
|
|
65
|
+
modal.Dict.objects.create("my-dict")
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Dicts will be created in the active environment, or another one can be specified:
|
|
69
|
+
|
|
70
|
+
```python notest
|
|
71
|
+
modal.Dict.objects.create("my-dict", environment_name="dev")
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
By default, an error will be raised if the Dict already exists, but passing
|
|
75
|
+
`allow_existing=True` will make the creation attempt a no-op in this case.
|
|
76
|
+
|
|
77
|
+
```python notest
|
|
78
|
+
modal.Dict.objects.create("my-dict", allow_existing=True)
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Note that this method does not return a local instance of the Dict. You can use
|
|
82
|
+
`modal.Dict.from_name` to perform a lookup after creation.
|
|
83
|
+
|
|
84
|
+
Added in v1.1.2.
|
|
85
|
+
|
|
86
|
+
"""
|
|
87
|
+
check_object_name(name, "Dict")
|
|
88
|
+
client = await _Client.from_env() if client is None else client
|
|
89
|
+
object_creation_type = (
|
|
90
|
+
api_pb2.OBJECT_CREATION_TYPE_CREATE_IF_MISSING
|
|
91
|
+
if allow_existing
|
|
92
|
+
else api_pb2.OBJECT_CREATION_TYPE_CREATE_FAIL_IF_EXISTS
|
|
93
|
+
)
|
|
94
|
+
req = api_pb2.DictGetOrCreateRequest(
|
|
95
|
+
deployment_name=name,
|
|
96
|
+
environment_name=_get_environment_name(environment_name),
|
|
97
|
+
object_creation_type=object_creation_type,
|
|
98
|
+
)
|
|
99
|
+
try:
|
|
100
|
+
await retry_transient_errors(client.stub.DictGetOrCreate, req)
|
|
101
|
+
except GRPCError as exc:
|
|
102
|
+
if exc.status == Status.ALREADY_EXISTS and not allow_existing:
|
|
103
|
+
raise AlreadyExistsError(exc.message)
|
|
104
|
+
else:
|
|
105
|
+
raise
|
|
106
|
+
|
|
107
|
+
@staticmethod
|
|
108
|
+
async def list(
|
|
109
|
+
*,
|
|
110
|
+
max_objects: Optional[int] = None, # Limit results to this size
|
|
111
|
+
created_before: Optional[Union[datetime, str]] = None, # Limit based on creation date
|
|
112
|
+
environment_name: str = "", # Uses active environment if not specified
|
|
113
|
+
client: Optional[_Client] = None, # Optional client with Modal credentials
|
|
114
|
+
) -> list["_Dict"]:
|
|
115
|
+
"""Return a list of hydrated Dict objects.
|
|
116
|
+
|
|
117
|
+
**Examples:**
|
|
118
|
+
|
|
119
|
+
```python
|
|
120
|
+
dicts = modal.Dict.objects.list()
|
|
121
|
+
print([d.name for d in dicts])
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Dicts will be retreived from the active environment, or another one can be specified:
|
|
125
|
+
|
|
126
|
+
```python notest
|
|
127
|
+
dev_dicts = modal.Dict.objects.list(environment_name="dev")
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
By default, all named Dict are returned, newest to oldest. It's also possible to limit the
|
|
131
|
+
number of results and to filter by creation date:
|
|
132
|
+
|
|
133
|
+
```python
|
|
134
|
+
dicts = modal.Dict.objects.list(max_objects=10, created_before="2025-01-01")
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Added in v1.1.2.
|
|
138
|
+
|
|
139
|
+
"""
|
|
140
|
+
client = await _Client.from_env() if client is None else client
|
|
141
|
+
if max_objects is not None and max_objects < 0:
|
|
142
|
+
raise InvalidError("max_objects cannot be negative")
|
|
143
|
+
|
|
144
|
+
items: list[api_pb2.DictListResponse.DictInfo] = []
|
|
145
|
+
|
|
146
|
+
async def retrieve_page(created_before: float) -> bool:
|
|
147
|
+
max_page_size = 100 if max_objects is None else min(100, max_objects - len(items))
|
|
148
|
+
pagination = api_pb2.ListPagination(max_objects=max_page_size, created_before=created_before)
|
|
149
|
+
req = api_pb2.DictListRequest(
|
|
150
|
+
environment_name=_get_environment_name(environment_name), pagination=pagination
|
|
151
|
+
)
|
|
152
|
+
resp = await retry_transient_errors(client.stub.DictList, req)
|
|
153
|
+
items.extend(resp.dicts)
|
|
154
|
+
finished = (len(resp.dicts) < max_page_size) or (max_objects is not None and len(items) >= max_objects)
|
|
155
|
+
return finished
|
|
156
|
+
|
|
157
|
+
finished = await retrieve_page(as_timestamp(created_before))
|
|
158
|
+
while True:
|
|
159
|
+
if finished:
|
|
160
|
+
break
|
|
161
|
+
finished = await retrieve_page(items[-1].metadata.creation_info.created_at)
|
|
162
|
+
|
|
163
|
+
dicts = [
|
|
164
|
+
_Dict._new_hydrated(
|
|
165
|
+
item.dict_id,
|
|
166
|
+
client,
|
|
167
|
+
item.metadata,
|
|
168
|
+
is_another_app=True,
|
|
169
|
+
rep=_Dict._repr(item.name, environment_name),
|
|
170
|
+
)
|
|
171
|
+
for item in items
|
|
172
|
+
]
|
|
173
|
+
return dicts[:max_objects] if max_objects is not None else dicts
|
|
174
|
+
|
|
175
|
+
@staticmethod
|
|
176
|
+
async def delete(
|
|
177
|
+
name: str, # Name of the Dict to delete
|
|
178
|
+
*,
|
|
179
|
+
allow_missing: bool = False, # If True, don't raise an error if the Dict doesn't exist
|
|
180
|
+
environment_name: Optional[str] = None, # Uses active environment if not specified
|
|
181
|
+
client: Optional[_Client] = None, # Optional client with Modal credentials
|
|
182
|
+
):
|
|
183
|
+
"""Delete a named Dict.
|
|
184
|
+
|
|
185
|
+
Warning: This deletes an *entire Dict*, not just a specific key.
|
|
186
|
+
Deletion is irreversible and will affect any Apps currently using the Dict.
|
|
187
|
+
|
|
188
|
+
**Examples:**
|
|
189
|
+
|
|
190
|
+
```python notest
|
|
191
|
+
await modal.Dict.objects.delete("my-dict")
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Dicts will be deleted from the active environment, or another one can be specified:
|
|
195
|
+
|
|
196
|
+
```python notest
|
|
197
|
+
await modal.Dict.objects.delete("my-dict", environment_name="dev")
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
Added in v1.1.2.
|
|
201
|
+
|
|
202
|
+
"""
|
|
203
|
+
try:
|
|
204
|
+
obj = await _Dict.from_name(name, environment_name=environment_name).hydrate(client)
|
|
205
|
+
except NotFoundError:
|
|
206
|
+
if not allow_missing:
|
|
207
|
+
raise
|
|
208
|
+
else:
|
|
209
|
+
req = api_pb2.DictDeleteRequest(dict_id=obj.object_id)
|
|
210
|
+
await retry_transient_errors(obj._client.stub.DictDelete, req)
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
DictManager = synchronize_api(_DictManager)
|
|
214
|
+
|
|
215
|
+
|
|
42
216
|
class _Dict(_Object, type_prefix="di"):
|
|
43
217
|
"""Distributed dictionary for storage in Modal apps.
|
|
44
218
|
|
|
@@ -90,6 +264,10 @@ class _Dict(_Object, type_prefix="di"):
|
|
|
90
264
|
"`Dict(...)` constructor is not allowed. Please use `Dict.from_name` or `Dict.ephemeral` instead"
|
|
91
265
|
)
|
|
92
266
|
|
|
267
|
+
@classproperty
|
|
268
|
+
def objects(cls) -> _DictManager:
|
|
269
|
+
return _DictManager
|
|
270
|
+
|
|
93
271
|
@property
|
|
94
272
|
def name(self) -> Optional[str]:
|
|
95
273
|
return self._name
|
|
@@ -111,7 +289,7 @@ class _Dict(_Object, type_prefix="di"):
|
|
|
111
289
|
data: Optional[dict] = None, # DEPRECATED
|
|
112
290
|
client: Optional[_Client] = None,
|
|
113
291
|
environment_name: Optional[str] = None,
|
|
114
|
-
_heartbeat_sleep: float = EPHEMERAL_OBJECT_HEARTBEAT_SLEEP,
|
|
292
|
+
_heartbeat_sleep: float = EPHEMERAL_OBJECT_HEARTBEAT_SLEEP, # mdmd:line-hidden
|
|
115
293
|
) -> AsyncIterator["_Dict"]:
|
|
116
294
|
"""Creates a new ephemeral Dict within a context manager:
|
|
117
295
|
|
|
@@ -145,7 +323,13 @@ class _Dict(_Object, type_prefix="di"):
|
|
|
145
323
|
async with TaskContext() as tc:
|
|
146
324
|
request = api_pb2.DictHeartbeatRequest(dict_id=response.dict_id)
|
|
147
325
|
tc.infinite_loop(lambda: client.stub.DictHeartbeat(request), sleep=_heartbeat_sleep)
|
|
148
|
-
yield cls._new_hydrated(
|
|
326
|
+
yield cls._new_hydrated(
|
|
327
|
+
response.dict_id,
|
|
328
|
+
client,
|
|
329
|
+
response.metadata,
|
|
330
|
+
is_another_app=True,
|
|
331
|
+
rep="modal.Dict.ephemeral()",
|
|
332
|
+
)
|
|
149
333
|
|
|
150
334
|
@staticmethod
|
|
151
335
|
def from_name(
|
|
@@ -188,7 +372,8 @@ class _Dict(_Object, type_prefix="di"):
|
|
|
188
372
|
logger.debug(f"Created dict with id {response.dict_id}")
|
|
189
373
|
self._hydrate(response.dict_id, resolver.client, response.metadata)
|
|
190
374
|
|
|
191
|
-
|
|
375
|
+
rep = _Dict._repr(name, environment_name)
|
|
376
|
+
return _Dict._from_loader(_load, rep, is_another_app=True, hydrate_lazily=True, name=name)
|
|
192
377
|
|
|
193
378
|
@staticmethod
|
|
194
379
|
async def lookup(
|
|
@@ -238,9 +423,18 @@ class _Dict(_Object, type_prefix="di"):
|
|
|
238
423
|
client: Optional[_Client] = None,
|
|
239
424
|
environment_name: Optional[str] = None,
|
|
240
425
|
):
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
426
|
+
"""mdmd:hidden
|
|
427
|
+
Delete a named Dict object.
|
|
428
|
+
|
|
429
|
+
Warning: This deletes an *entire Dict*, not just a specific key.
|
|
430
|
+
Deletion is irreversible and will affect any Apps currently using the Dict.
|
|
431
|
+
|
|
432
|
+
DEPRECATED: This method is deprecated; we recommend using `modal.Dict.objects.delete` instead.
|
|
433
|
+
"""
|
|
434
|
+
deprecation_warning(
|
|
435
|
+
(2025, 8, 6), "`modal.Dict.delete` is deprecated; we recommend using `modal.Dict.objects.delete` instead."
|
|
436
|
+
)
|
|
437
|
+
await _Dict.objects.delete(name, environment_name=environment_name, client=client)
|
|
244
438
|
|
|
245
439
|
@live_method
|
|
246
440
|
async def info(self) -> DictInfo:
|
modal/dict.pyi
CHANGED
|
@@ -5,6 +5,7 @@ import modal._object
|
|
|
5
5
|
import modal.client
|
|
6
6
|
import modal.object
|
|
7
7
|
import modal_proto.api_pb2
|
|
8
|
+
import synchronicity
|
|
8
9
|
import synchronicity.combined_types
|
|
9
10
|
import typing
|
|
10
11
|
import typing_extensions
|
|
@@ -12,7 +13,7 @@ import typing_extensions
|
|
|
12
13
|
def _serialize_dict(data): ...
|
|
13
14
|
|
|
14
15
|
class DictInfo:
|
|
15
|
-
"""Information about
|
|
16
|
+
"""Information about a Dict object."""
|
|
16
17
|
|
|
17
18
|
name: typing.Optional[str]
|
|
18
19
|
created_at: datetime.datetime
|
|
@@ -32,6 +33,326 @@ class DictInfo:
|
|
|
32
33
|
"""Return self==value."""
|
|
33
34
|
...
|
|
34
35
|
|
|
36
|
+
class _DictManager:
|
|
37
|
+
"""Namespace with methods for managing named Dict objects."""
|
|
38
|
+
@staticmethod
|
|
39
|
+
async def create(
|
|
40
|
+
name: str,
|
|
41
|
+
*,
|
|
42
|
+
allow_existing: bool = False,
|
|
43
|
+
environment_name: typing.Optional[str] = None,
|
|
44
|
+
client: typing.Optional[modal.client._Client] = None,
|
|
45
|
+
) -> None:
|
|
46
|
+
"""Create a new Dict object.
|
|
47
|
+
|
|
48
|
+
**Examples:**
|
|
49
|
+
|
|
50
|
+
```python notest
|
|
51
|
+
modal.Dict.objects.create("my-dict")
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Dicts will be created in the active environment, or another one can be specified:
|
|
55
|
+
|
|
56
|
+
```python notest
|
|
57
|
+
modal.Dict.objects.create("my-dict", environment_name="dev")
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
By default, an error will be raised if the Dict already exists, but passing
|
|
61
|
+
`allow_existing=True` will make the creation attempt a no-op in this case.
|
|
62
|
+
|
|
63
|
+
```python notest
|
|
64
|
+
modal.Dict.objects.create("my-dict", allow_existing=True)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Note that this method does not return a local instance of the Dict. You can use
|
|
68
|
+
`modal.Dict.from_name` to perform a lookup after creation.
|
|
69
|
+
|
|
70
|
+
Added in v1.1.2.
|
|
71
|
+
"""
|
|
72
|
+
...
|
|
73
|
+
|
|
74
|
+
@staticmethod
|
|
75
|
+
async def list(
|
|
76
|
+
*,
|
|
77
|
+
max_objects: typing.Optional[int] = None,
|
|
78
|
+
created_before: typing.Union[datetime.datetime, str, None] = None,
|
|
79
|
+
environment_name: str = "",
|
|
80
|
+
client: typing.Optional[modal.client._Client] = None,
|
|
81
|
+
) -> list[_Dict]:
|
|
82
|
+
"""Return a list of hydrated Dict objects.
|
|
83
|
+
|
|
84
|
+
**Examples:**
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
dicts = modal.Dict.objects.list()
|
|
88
|
+
print([d.name for d in dicts])
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Dicts will be retreived from the active environment, or another one can be specified:
|
|
92
|
+
|
|
93
|
+
```python notest
|
|
94
|
+
dev_dicts = modal.Dict.objects.list(environment_name="dev")
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
By default, all named Dict are returned, newest to oldest. It's also possible to limit the
|
|
98
|
+
number of results and to filter by creation date:
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
dicts = modal.Dict.objects.list(max_objects=10, created_before="2025-01-01")
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Added in v1.1.2.
|
|
105
|
+
"""
|
|
106
|
+
...
|
|
107
|
+
|
|
108
|
+
@staticmethod
|
|
109
|
+
async def delete(
|
|
110
|
+
name: str,
|
|
111
|
+
*,
|
|
112
|
+
allow_missing: bool = False,
|
|
113
|
+
environment_name: typing.Optional[str] = None,
|
|
114
|
+
client: typing.Optional[modal.client._Client] = None,
|
|
115
|
+
):
|
|
116
|
+
"""Delete a named Dict.
|
|
117
|
+
|
|
118
|
+
Warning: This deletes an *entire Dict*, not just a specific key.
|
|
119
|
+
Deletion is irreversible and will affect any Apps currently using the Dict.
|
|
120
|
+
|
|
121
|
+
**Examples:**
|
|
122
|
+
|
|
123
|
+
```python notest
|
|
124
|
+
await modal.Dict.objects.delete("my-dict")
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Dicts will be deleted from the active environment, or another one can be specified:
|
|
128
|
+
|
|
129
|
+
```python notest
|
|
130
|
+
await modal.Dict.objects.delete("my-dict", environment_name="dev")
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Added in v1.1.2.
|
|
134
|
+
"""
|
|
135
|
+
...
|
|
136
|
+
|
|
137
|
+
class DictManager:
|
|
138
|
+
"""Namespace with methods for managing named Dict objects."""
|
|
139
|
+
def __init__(self, /, *args, **kwargs):
|
|
140
|
+
"""Initialize self. See help(type(self)) for accurate signature."""
|
|
141
|
+
...
|
|
142
|
+
|
|
143
|
+
class __create_spec(typing_extensions.Protocol):
|
|
144
|
+
def __call__(
|
|
145
|
+
self,
|
|
146
|
+
/,
|
|
147
|
+
name: str,
|
|
148
|
+
*,
|
|
149
|
+
allow_existing: bool = False,
|
|
150
|
+
environment_name: typing.Optional[str] = None,
|
|
151
|
+
client: typing.Optional[modal.client.Client] = None,
|
|
152
|
+
) -> None:
|
|
153
|
+
"""Create a new Dict object.
|
|
154
|
+
|
|
155
|
+
**Examples:**
|
|
156
|
+
|
|
157
|
+
```python notest
|
|
158
|
+
modal.Dict.objects.create("my-dict")
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Dicts will be created in the active environment, or another one can be specified:
|
|
162
|
+
|
|
163
|
+
```python notest
|
|
164
|
+
modal.Dict.objects.create("my-dict", environment_name="dev")
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
By default, an error will be raised if the Dict already exists, but passing
|
|
168
|
+
`allow_existing=True` will make the creation attempt a no-op in this case.
|
|
169
|
+
|
|
170
|
+
```python notest
|
|
171
|
+
modal.Dict.objects.create("my-dict", allow_existing=True)
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Note that this method does not return a local instance of the Dict. You can use
|
|
175
|
+
`modal.Dict.from_name` to perform a lookup after creation.
|
|
176
|
+
|
|
177
|
+
Added in v1.1.2.
|
|
178
|
+
"""
|
|
179
|
+
...
|
|
180
|
+
|
|
181
|
+
async def aio(
|
|
182
|
+
self,
|
|
183
|
+
/,
|
|
184
|
+
name: str,
|
|
185
|
+
*,
|
|
186
|
+
allow_existing: bool = False,
|
|
187
|
+
environment_name: typing.Optional[str] = None,
|
|
188
|
+
client: typing.Optional[modal.client.Client] = None,
|
|
189
|
+
) -> None:
|
|
190
|
+
"""Create a new Dict object.
|
|
191
|
+
|
|
192
|
+
**Examples:**
|
|
193
|
+
|
|
194
|
+
```python notest
|
|
195
|
+
modal.Dict.objects.create("my-dict")
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Dicts will be created in the active environment, or another one can be specified:
|
|
199
|
+
|
|
200
|
+
```python notest
|
|
201
|
+
modal.Dict.objects.create("my-dict", environment_name="dev")
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
By default, an error will be raised if the Dict already exists, but passing
|
|
205
|
+
`allow_existing=True` will make the creation attempt a no-op in this case.
|
|
206
|
+
|
|
207
|
+
```python notest
|
|
208
|
+
modal.Dict.objects.create("my-dict", allow_existing=True)
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
Note that this method does not return a local instance of the Dict. You can use
|
|
212
|
+
`modal.Dict.from_name` to perform a lookup after creation.
|
|
213
|
+
|
|
214
|
+
Added in v1.1.2.
|
|
215
|
+
"""
|
|
216
|
+
...
|
|
217
|
+
|
|
218
|
+
create: __create_spec
|
|
219
|
+
|
|
220
|
+
class __list_spec(typing_extensions.Protocol):
|
|
221
|
+
def __call__(
|
|
222
|
+
self,
|
|
223
|
+
/,
|
|
224
|
+
*,
|
|
225
|
+
max_objects: typing.Optional[int] = None,
|
|
226
|
+
created_before: typing.Union[datetime.datetime, str, None] = None,
|
|
227
|
+
environment_name: str = "",
|
|
228
|
+
client: typing.Optional[modal.client.Client] = None,
|
|
229
|
+
) -> list[Dict]:
|
|
230
|
+
"""Return a list of hydrated Dict objects.
|
|
231
|
+
|
|
232
|
+
**Examples:**
|
|
233
|
+
|
|
234
|
+
```python
|
|
235
|
+
dicts = modal.Dict.objects.list()
|
|
236
|
+
print([d.name for d in dicts])
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
Dicts will be retreived from the active environment, or another one can be specified:
|
|
240
|
+
|
|
241
|
+
```python notest
|
|
242
|
+
dev_dicts = modal.Dict.objects.list(environment_name="dev")
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
By default, all named Dict are returned, newest to oldest. It's also possible to limit the
|
|
246
|
+
number of results and to filter by creation date:
|
|
247
|
+
|
|
248
|
+
```python
|
|
249
|
+
dicts = modal.Dict.objects.list(max_objects=10, created_before="2025-01-01")
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
Added in v1.1.2.
|
|
253
|
+
"""
|
|
254
|
+
...
|
|
255
|
+
|
|
256
|
+
async def aio(
|
|
257
|
+
self,
|
|
258
|
+
/,
|
|
259
|
+
*,
|
|
260
|
+
max_objects: typing.Optional[int] = None,
|
|
261
|
+
created_before: typing.Union[datetime.datetime, str, None] = None,
|
|
262
|
+
environment_name: str = "",
|
|
263
|
+
client: typing.Optional[modal.client.Client] = None,
|
|
264
|
+
) -> list[Dict]:
|
|
265
|
+
"""Return a list of hydrated Dict objects.
|
|
266
|
+
|
|
267
|
+
**Examples:**
|
|
268
|
+
|
|
269
|
+
```python
|
|
270
|
+
dicts = modal.Dict.objects.list()
|
|
271
|
+
print([d.name for d in dicts])
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
Dicts will be retreived from the active environment, or another one can be specified:
|
|
275
|
+
|
|
276
|
+
```python notest
|
|
277
|
+
dev_dicts = modal.Dict.objects.list(environment_name="dev")
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
By default, all named Dict are returned, newest to oldest. It's also possible to limit the
|
|
281
|
+
number of results and to filter by creation date:
|
|
282
|
+
|
|
283
|
+
```python
|
|
284
|
+
dicts = modal.Dict.objects.list(max_objects=10, created_before="2025-01-01")
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
Added in v1.1.2.
|
|
288
|
+
"""
|
|
289
|
+
...
|
|
290
|
+
|
|
291
|
+
list: __list_spec
|
|
292
|
+
|
|
293
|
+
class __delete_spec(typing_extensions.Protocol):
|
|
294
|
+
def __call__(
|
|
295
|
+
self,
|
|
296
|
+
/,
|
|
297
|
+
name: str,
|
|
298
|
+
*,
|
|
299
|
+
allow_missing: bool = False,
|
|
300
|
+
environment_name: typing.Optional[str] = None,
|
|
301
|
+
client: typing.Optional[modal.client.Client] = None,
|
|
302
|
+
):
|
|
303
|
+
"""Delete a named Dict.
|
|
304
|
+
|
|
305
|
+
Warning: This deletes an *entire Dict*, not just a specific key.
|
|
306
|
+
Deletion is irreversible and will affect any Apps currently using the Dict.
|
|
307
|
+
|
|
308
|
+
**Examples:**
|
|
309
|
+
|
|
310
|
+
```python notest
|
|
311
|
+
await modal.Dict.objects.delete("my-dict")
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
Dicts will be deleted from the active environment, or another one can be specified:
|
|
315
|
+
|
|
316
|
+
```python notest
|
|
317
|
+
await modal.Dict.objects.delete("my-dict", environment_name="dev")
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
Added in v1.1.2.
|
|
321
|
+
"""
|
|
322
|
+
...
|
|
323
|
+
|
|
324
|
+
async def aio(
|
|
325
|
+
self,
|
|
326
|
+
/,
|
|
327
|
+
name: str,
|
|
328
|
+
*,
|
|
329
|
+
allow_missing: bool = False,
|
|
330
|
+
environment_name: typing.Optional[str] = None,
|
|
331
|
+
client: typing.Optional[modal.client.Client] = None,
|
|
332
|
+
):
|
|
333
|
+
"""Delete a named Dict.
|
|
334
|
+
|
|
335
|
+
Warning: This deletes an *entire Dict*, not just a specific key.
|
|
336
|
+
Deletion is irreversible and will affect any Apps currently using the Dict.
|
|
337
|
+
|
|
338
|
+
**Examples:**
|
|
339
|
+
|
|
340
|
+
```python notest
|
|
341
|
+
await modal.Dict.objects.delete("my-dict")
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
Dicts will be deleted from the active environment, or another one can be specified:
|
|
345
|
+
|
|
346
|
+
```python notest
|
|
347
|
+
await modal.Dict.objects.delete("my-dict", environment_name="dev")
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
Added in v1.1.2.
|
|
351
|
+
"""
|
|
352
|
+
...
|
|
353
|
+
|
|
354
|
+
delete: __delete_spec
|
|
355
|
+
|
|
35
356
|
class _Dict(modal._object._Object):
|
|
36
357
|
"""Distributed dictionary for storage in Modal apps.
|
|
37
358
|
|
|
@@ -81,6 +402,8 @@ class _Dict(modal._object._Object):
|
|
|
81
402
|
"""mdmd:hidden"""
|
|
82
403
|
...
|
|
83
404
|
|
|
405
|
+
@synchronicity.classproperty
|
|
406
|
+
def objects(cls) -> _DictManager: ...
|
|
84
407
|
@property
|
|
85
408
|
def name(self) -> typing.Optional[str]: ...
|
|
86
409
|
def _hydrate_metadata(self, metadata: typing.Optional[google.protobuf.message.Message]): ...
|
|
@@ -162,7 +485,17 @@ class _Dict(modal._object._Object):
|
|
|
162
485
|
*,
|
|
163
486
|
client: typing.Optional[modal.client._Client] = None,
|
|
164
487
|
environment_name: typing.Optional[str] = None,
|
|
165
|
-
):
|
|
488
|
+
):
|
|
489
|
+
"""mdmd:hidden
|
|
490
|
+
Delete a named Dict object.
|
|
491
|
+
|
|
492
|
+
Warning: This deletes an *entire Dict*, not just a specific key.
|
|
493
|
+
Deletion is irreversible and will affect any Apps currently using the Dict.
|
|
494
|
+
|
|
495
|
+
DEPRECATED: This method is deprecated; we recommend using `modal.Dict.objects.delete` instead.
|
|
496
|
+
"""
|
|
497
|
+
...
|
|
498
|
+
|
|
166
499
|
async def info(self) -> DictInfo:
|
|
167
500
|
"""Return information about the Dict object."""
|
|
168
501
|
...
|
|
@@ -308,6 +641,8 @@ class Dict(modal.object.Object):
|
|
|
308
641
|
"""mdmd:hidden"""
|
|
309
642
|
...
|
|
310
643
|
|
|
644
|
+
@synchronicity.classproperty
|
|
645
|
+
def objects(cls) -> DictManager: ...
|
|
311
646
|
@property
|
|
312
647
|
def name(self) -> typing.Optional[str]: ...
|
|
313
648
|
def _hydrate_metadata(self, metadata: typing.Optional[google.protobuf.message.Message]): ...
|
|
@@ -420,7 +755,17 @@ class Dict(modal.object.Object):
|
|
|
420
755
|
*,
|
|
421
756
|
client: typing.Optional[modal.client.Client] = None,
|
|
422
757
|
environment_name: typing.Optional[str] = None,
|
|
423
|
-
):
|
|
758
|
+
):
|
|
759
|
+
"""mdmd:hidden
|
|
760
|
+
Delete a named Dict object.
|
|
761
|
+
|
|
762
|
+
Warning: This deletes an *entire Dict*, not just a specific key.
|
|
763
|
+
Deletion is irreversible and will affect any Apps currently using the Dict.
|
|
764
|
+
|
|
765
|
+
DEPRECATED: This method is deprecated; we recommend using `modal.Dict.objects.delete` instead.
|
|
766
|
+
"""
|
|
767
|
+
...
|
|
768
|
+
|
|
424
769
|
async def aio(
|
|
425
770
|
self,
|
|
426
771
|
/,
|
|
@@ -428,7 +773,16 @@ class Dict(modal.object.Object):
|
|
|
428
773
|
*,
|
|
429
774
|
client: typing.Optional[modal.client.Client] = None,
|
|
430
775
|
environment_name: typing.Optional[str] = None,
|
|
431
|
-
):
|
|
776
|
+
):
|
|
777
|
+
"""mdmd:hidden
|
|
778
|
+
Delete a named Dict object.
|
|
779
|
+
|
|
780
|
+
Warning: This deletes an *entire Dict*, not just a specific key.
|
|
781
|
+
Deletion is irreversible and will affect any Apps currently using the Dict.
|
|
782
|
+
|
|
783
|
+
DEPRECATED: This method is deprecated; we recommend using `modal.Dict.objects.delete` instead.
|
|
784
|
+
"""
|
|
785
|
+
...
|
|
432
786
|
|
|
433
787
|
delete: __delete_spec
|
|
434
788
|
|