modal 1.0.6.dev58__py3-none-any.whl → 1.2.3.dev7__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 +3 -4
- modal/_billing.py +80 -0
- modal/_clustered_functions.py +7 -3
- modal/_clustered_functions.pyi +4 -2
- modal/_container_entrypoint.py +41 -49
- modal/_functions.py +424 -195
- modal/_grpc_client.py +171 -0
- modal/_load_context.py +105 -0
- modal/_object.py +68 -20
- modal/_output.py +58 -45
- modal/_partial_function.py +36 -11
- modal/_pty.py +7 -3
- modal/_resolver.py +21 -35
- modal/_runtime/asgi.py +4 -3
- modal/_runtime/container_io_manager.py +301 -186
- modal/_runtime/container_io_manager.pyi +70 -61
- modal/_runtime/execution_context.py +18 -2
- modal/_runtime/execution_context.pyi +4 -1
- modal/_runtime/gpu_memory_snapshot.py +170 -63
- modal/_runtime/user_code_imports.py +28 -58
- modal/_serialization.py +57 -1
- modal/_utils/async_utils.py +33 -12
- modal/_utils/auth_token_manager.py +2 -5
- modal/_utils/blob_utils.py +110 -53
- modal/_utils/function_utils.py +49 -42
- modal/_utils/grpc_utils.py +80 -50
- modal/_utils/mount_utils.py +26 -1
- modal/_utils/name_utils.py +17 -3
- modal/_utils/task_command_router_client.py +536 -0
- modal/_utils/time_utils.py +34 -6
- modal/app.py +219 -83
- modal/app.pyi +229 -56
- modal/billing.py +5 -0
- modal/{requirements → builder}/2025.06.txt +1 -0
- modal/{requirements → builder}/PREVIEW.txt +1 -0
- modal/cli/_download.py +19 -3
- modal/cli/_traceback.py +3 -2
- modal/cli/app.py +4 -4
- modal/cli/cluster.py +15 -7
- modal/cli/config.py +5 -3
- modal/cli/container.py +7 -6
- modal/cli/dict.py +22 -16
- modal/cli/entry_point.py +12 -5
- modal/cli/environment.py +5 -4
- modal/cli/import_refs.py +3 -3
- modal/cli/launch.py +102 -5
- modal/cli/network_file_system.py +9 -13
- modal/cli/profile.py +3 -2
- modal/cli/programs/launch_instance_ssh.py +94 -0
- modal/cli/programs/run_jupyter.py +1 -1
- modal/cli/programs/run_marimo.py +95 -0
- modal/cli/programs/vscode.py +1 -1
- modal/cli/queues.py +57 -26
- modal/cli/run.py +58 -16
- modal/cli/secret.py +48 -22
- modal/cli/utils.py +3 -4
- modal/cli/volume.py +28 -25
- modal/client.py +13 -116
- modal/client.pyi +9 -91
- modal/cloud_bucket_mount.py +5 -3
- modal/cloud_bucket_mount.pyi +5 -1
- modal/cls.py +130 -102
- modal/cls.pyi +45 -85
- modal/config.py +29 -10
- modal/container_process.py +291 -13
- modal/container_process.pyi +95 -32
- modal/dict.py +282 -63
- modal/dict.pyi +423 -73
- modal/environments.py +15 -27
- modal/environments.pyi +5 -15
- modal/exception.py +8 -0
- modal/experimental/__init__.py +143 -38
- modal/experimental/flash.py +247 -78
- modal/experimental/flash.pyi +137 -9
- modal/file_io.py +14 -28
- modal/file_io.pyi +2 -2
- modal/file_pattern_matcher.py +25 -16
- modal/functions.pyi +134 -61
- modal/image.py +255 -86
- modal/image.pyi +300 -62
- modal/io_streams.py +436 -126
- modal/io_streams.pyi +236 -171
- modal/mount.py +62 -157
- modal/mount.pyi +45 -172
- modal/network_file_system.py +30 -53
- modal/network_file_system.pyi +16 -76
- modal/object.pyi +42 -8
- modal/parallel_map.py +821 -113
- modal/parallel_map.pyi +134 -0
- modal/partial_function.pyi +4 -1
- modal/proxy.py +16 -7
- modal/proxy.pyi +10 -2
- modal/queue.py +263 -61
- modal/queue.pyi +409 -66
- modal/runner.py +112 -92
- modal/runner.pyi +45 -27
- modal/sandbox.py +451 -124
- modal/sandbox.pyi +513 -67
- modal/secret.py +291 -67
- modal/secret.pyi +425 -19
- modal/serving.py +7 -11
- modal/serving.pyi +7 -8
- modal/snapshot.py +11 -8
- modal/token_flow.py +4 -4
- modal/volume.py +344 -98
- modal/volume.pyi +464 -68
- {modal-1.0.6.dev58.dist-info → modal-1.2.3.dev7.dist-info}/METADATA +9 -8
- modal-1.2.3.dev7.dist-info/RECORD +195 -0
- modal_docs/mdmd/mdmd.py +11 -1
- modal_proto/api.proto +399 -67
- modal_proto/api_grpc.py +241 -1
- modal_proto/api_pb2.py +1395 -1000
- modal_proto/api_pb2.pyi +1239 -79
- modal_proto/api_pb2_grpc.py +499 -4
- modal_proto/api_pb2_grpc.pyi +162 -14
- modal_proto/modal_api_grpc.py +175 -160
- modal_proto/sandbox_router.proto +145 -0
- modal_proto/sandbox_router_grpc.py +105 -0
- modal_proto/sandbox_router_pb2.py +149 -0
- modal_proto/sandbox_router_pb2.pyi +333 -0
- modal_proto/sandbox_router_pb2_grpc.py +203 -0
- modal_proto/sandbox_router_pb2_grpc.pyi +75 -0
- modal_proto/task_command_router.proto +144 -0
- modal_proto/task_command_router_grpc.py +105 -0
- modal_proto/task_command_router_pb2.py +149 -0
- modal_proto/task_command_router_pb2.pyi +333 -0
- modal_proto/task_command_router_pb2_grpc.py +203 -0
- modal_proto/task_command_router_pb2_grpc.pyi +75 -0
- modal_version/__init__.py +1 -1
- modal-1.0.6.dev58.dist-info/RECORD +0 -183
- modal_proto/modal_options_grpc.py +0 -3
- modal_proto/options.proto +0 -19
- modal_proto/options_grpc.py +0 -3
- modal_proto/options_pb2.py +0 -35
- modal_proto/options_pb2.pyi +0 -20
- modal_proto/options_pb2_grpc.py +0 -4
- modal_proto/options_pb2_grpc.pyi +0 -7
- /modal/{requirements → builder}/2023.12.312.txt +0 -0
- /modal/{requirements → builder}/2023.12.txt +0 -0
- /modal/{requirements → builder}/2024.04.txt +0 -0
- /modal/{requirements → builder}/2024.10.txt +0 -0
- /modal/{requirements → builder}/README.md +0 -0
- /modal/{requirements → builder}/base-images.json +0 -0
- {modal-1.0.6.dev58.dist-info → modal-1.2.3.dev7.dist-info}/WHEEL +0 -0
- {modal-1.0.6.dev58.dist-info → modal-1.2.3.dev7.dist-info}/entry_points.txt +0 -0
- {modal-1.0.6.dev58.dist-info → modal-1.2.3.dev7.dist-info}/licenses/LICENSE +0 -0
- {modal-1.0.6.dev58.dist-info → modal-1.2.3.dev7.dist-info}/top_level.txt +0 -0
modal/secret.pyi
CHANGED
|
@@ -1,9 +1,367 @@
|
|
|
1
|
+
import datetime
|
|
2
|
+
import google.protobuf.message
|
|
3
|
+
import modal._load_context
|
|
1
4
|
import modal._object
|
|
2
5
|
import modal.client
|
|
3
6
|
import modal.object
|
|
7
|
+
import modal_proto.api_pb2
|
|
8
|
+
import synchronicity
|
|
4
9
|
import typing
|
|
5
10
|
import typing_extensions
|
|
6
11
|
|
|
12
|
+
class SecretInfo:
|
|
13
|
+
"""Information about the Secret object."""
|
|
14
|
+
|
|
15
|
+
name: typing.Optional[str]
|
|
16
|
+
created_at: datetime.datetime
|
|
17
|
+
created_by: typing.Optional[str]
|
|
18
|
+
|
|
19
|
+
def __init__(
|
|
20
|
+
self, name: typing.Optional[str], created_at: datetime.datetime, created_by: typing.Optional[str]
|
|
21
|
+
) -> None:
|
|
22
|
+
"""Initialize self. See help(type(self)) for accurate signature."""
|
|
23
|
+
...
|
|
24
|
+
|
|
25
|
+
def __repr__(self):
|
|
26
|
+
"""Return repr(self)."""
|
|
27
|
+
...
|
|
28
|
+
|
|
29
|
+
def __eq__(self, other):
|
|
30
|
+
"""Return self==value."""
|
|
31
|
+
...
|
|
32
|
+
|
|
33
|
+
class _SecretManager:
|
|
34
|
+
"""Namespace with methods for managing named Secret objects."""
|
|
35
|
+
@staticmethod
|
|
36
|
+
async def create(
|
|
37
|
+
name: str,
|
|
38
|
+
env_dict: dict[str, str],
|
|
39
|
+
*,
|
|
40
|
+
allow_existing: bool = False,
|
|
41
|
+
environment_name: typing.Optional[str] = None,
|
|
42
|
+
client: typing.Optional[modal.client._Client] = None,
|
|
43
|
+
) -> None:
|
|
44
|
+
"""Create a new Secret object.
|
|
45
|
+
|
|
46
|
+
**Examples:**
|
|
47
|
+
|
|
48
|
+
```python notest
|
|
49
|
+
contents = {"MY_KEY": "my-value", "MY_OTHER_KEY": "my-other-value"}
|
|
50
|
+
modal.Secret.objects.create("my-secret", contents)
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Secrets will be created in the active environment, or another one can be specified:
|
|
54
|
+
|
|
55
|
+
```python notest
|
|
56
|
+
modal.Secret.objects.create("my-secret", contents, environment_name="dev")
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
By default, an error will be raised if the Secret already exists, but passing
|
|
60
|
+
`allow_existing=True` will make the creation attempt a no-op in this case.
|
|
61
|
+
If the `env_dict` data differs from the existing Secret, it will be ignored.
|
|
62
|
+
|
|
63
|
+
```python notest
|
|
64
|
+
modal.Secret.objects.create("my-secret", contents, allow_existing=True)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Note that this method does not return a local instance of the Secret. You can use
|
|
68
|
+
`modal.Secret.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[_Secret]:
|
|
82
|
+
"""Return a list of hydrated Secret objects.
|
|
83
|
+
|
|
84
|
+
**Examples:**
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
secrets = modal.Secret.objects.list()
|
|
88
|
+
print([s.name for s in secrets])
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Secrets will be retreived from the active environment, or another one can be specified:
|
|
92
|
+
|
|
93
|
+
```python notest
|
|
94
|
+
dev_secrets = modal.Secret.objects.list(environment_name="dev")
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
By default, all named Secrets 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
|
+
secrets = modal.Secret.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 Secret.
|
|
117
|
+
|
|
118
|
+
Warning: Deletion is irreversible and will affect any Apps currently using the Secret.
|
|
119
|
+
|
|
120
|
+
**Examples:**
|
|
121
|
+
|
|
122
|
+
```python notest
|
|
123
|
+
await modal.Secret.objects.delete("my-secret")
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Secrets will be deleted from the active environment, or another one can be specified:
|
|
127
|
+
|
|
128
|
+
```python notest
|
|
129
|
+
await modal.Secret.objects.delete("my-secret", environment_name="dev")
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Added in v1.1.2.
|
|
133
|
+
"""
|
|
134
|
+
...
|
|
135
|
+
|
|
136
|
+
class SecretManager:
|
|
137
|
+
"""Namespace with methods for managing named Secret objects."""
|
|
138
|
+
def __init__(self, /, *args, **kwargs):
|
|
139
|
+
"""Initialize self. See help(type(self)) for accurate signature."""
|
|
140
|
+
...
|
|
141
|
+
|
|
142
|
+
class __create_spec(typing_extensions.Protocol):
|
|
143
|
+
def __call__(
|
|
144
|
+
self,
|
|
145
|
+
/,
|
|
146
|
+
name: str,
|
|
147
|
+
env_dict: dict[str, 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 Secret object.
|
|
154
|
+
|
|
155
|
+
**Examples:**
|
|
156
|
+
|
|
157
|
+
```python notest
|
|
158
|
+
contents = {"MY_KEY": "my-value", "MY_OTHER_KEY": "my-other-value"}
|
|
159
|
+
modal.Secret.objects.create("my-secret", contents)
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Secrets will be created in the active environment, or another one can be specified:
|
|
163
|
+
|
|
164
|
+
```python notest
|
|
165
|
+
modal.Secret.objects.create("my-secret", contents, environment_name="dev")
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
By default, an error will be raised if the Secret already exists, but passing
|
|
169
|
+
`allow_existing=True` will make the creation attempt a no-op in this case.
|
|
170
|
+
If the `env_dict` data differs from the existing Secret, it will be ignored.
|
|
171
|
+
|
|
172
|
+
```python notest
|
|
173
|
+
modal.Secret.objects.create("my-secret", contents, allow_existing=True)
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Note that this method does not return a local instance of the Secret. You can use
|
|
177
|
+
`modal.Secret.from_name` to perform a lookup after creation.
|
|
178
|
+
|
|
179
|
+
Added in v1.1.2.
|
|
180
|
+
"""
|
|
181
|
+
...
|
|
182
|
+
|
|
183
|
+
async def aio(
|
|
184
|
+
self,
|
|
185
|
+
/,
|
|
186
|
+
name: str,
|
|
187
|
+
env_dict: dict[str, str],
|
|
188
|
+
*,
|
|
189
|
+
allow_existing: bool = False,
|
|
190
|
+
environment_name: typing.Optional[str] = None,
|
|
191
|
+
client: typing.Optional[modal.client.Client] = None,
|
|
192
|
+
) -> None:
|
|
193
|
+
"""Create a new Secret object.
|
|
194
|
+
|
|
195
|
+
**Examples:**
|
|
196
|
+
|
|
197
|
+
```python notest
|
|
198
|
+
contents = {"MY_KEY": "my-value", "MY_OTHER_KEY": "my-other-value"}
|
|
199
|
+
modal.Secret.objects.create("my-secret", contents)
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Secrets will be created in the active environment, or another one can be specified:
|
|
203
|
+
|
|
204
|
+
```python notest
|
|
205
|
+
modal.Secret.objects.create("my-secret", contents, environment_name="dev")
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
By default, an error will be raised if the Secret already exists, but passing
|
|
209
|
+
`allow_existing=True` will make the creation attempt a no-op in this case.
|
|
210
|
+
If the `env_dict` data differs from the existing Secret, it will be ignored.
|
|
211
|
+
|
|
212
|
+
```python notest
|
|
213
|
+
modal.Secret.objects.create("my-secret", contents, allow_existing=True)
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
Note that this method does not return a local instance of the Secret. You can use
|
|
217
|
+
`modal.Secret.from_name` to perform a lookup after creation.
|
|
218
|
+
|
|
219
|
+
Added in v1.1.2.
|
|
220
|
+
"""
|
|
221
|
+
...
|
|
222
|
+
|
|
223
|
+
create: __create_spec
|
|
224
|
+
|
|
225
|
+
class __list_spec(typing_extensions.Protocol):
|
|
226
|
+
def __call__(
|
|
227
|
+
self,
|
|
228
|
+
/,
|
|
229
|
+
*,
|
|
230
|
+
max_objects: typing.Optional[int] = None,
|
|
231
|
+
created_before: typing.Union[datetime.datetime, str, None] = None,
|
|
232
|
+
environment_name: str = "",
|
|
233
|
+
client: typing.Optional[modal.client.Client] = None,
|
|
234
|
+
) -> list[Secret]:
|
|
235
|
+
"""Return a list of hydrated Secret objects.
|
|
236
|
+
|
|
237
|
+
**Examples:**
|
|
238
|
+
|
|
239
|
+
```python
|
|
240
|
+
secrets = modal.Secret.objects.list()
|
|
241
|
+
print([s.name for s in secrets])
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
Secrets will be retreived from the active environment, or another one can be specified:
|
|
245
|
+
|
|
246
|
+
```python notest
|
|
247
|
+
dev_secrets = modal.Secret.objects.list(environment_name="dev")
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
By default, all named Secrets are returned, newest to oldest. It's also possible to limit the
|
|
251
|
+
number of results and to filter by creation date:
|
|
252
|
+
|
|
253
|
+
```python
|
|
254
|
+
secrets = modal.Secret.objects.list(max_objects=10, created_before="2025-01-01")
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
Added in v1.1.2.
|
|
258
|
+
"""
|
|
259
|
+
...
|
|
260
|
+
|
|
261
|
+
async def aio(
|
|
262
|
+
self,
|
|
263
|
+
/,
|
|
264
|
+
*,
|
|
265
|
+
max_objects: typing.Optional[int] = None,
|
|
266
|
+
created_before: typing.Union[datetime.datetime, str, None] = None,
|
|
267
|
+
environment_name: str = "",
|
|
268
|
+
client: typing.Optional[modal.client.Client] = None,
|
|
269
|
+
) -> list[Secret]:
|
|
270
|
+
"""Return a list of hydrated Secret objects.
|
|
271
|
+
|
|
272
|
+
**Examples:**
|
|
273
|
+
|
|
274
|
+
```python
|
|
275
|
+
secrets = modal.Secret.objects.list()
|
|
276
|
+
print([s.name for s in secrets])
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
Secrets will be retreived from the active environment, or another one can be specified:
|
|
280
|
+
|
|
281
|
+
```python notest
|
|
282
|
+
dev_secrets = modal.Secret.objects.list(environment_name="dev")
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
By default, all named Secrets are returned, newest to oldest. It's also possible to limit the
|
|
286
|
+
number of results and to filter by creation date:
|
|
287
|
+
|
|
288
|
+
```python
|
|
289
|
+
secrets = modal.Secret.objects.list(max_objects=10, created_before="2025-01-01")
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
Added in v1.1.2.
|
|
293
|
+
"""
|
|
294
|
+
...
|
|
295
|
+
|
|
296
|
+
list: __list_spec
|
|
297
|
+
|
|
298
|
+
class __delete_spec(typing_extensions.Protocol):
|
|
299
|
+
def __call__(
|
|
300
|
+
self,
|
|
301
|
+
/,
|
|
302
|
+
name: str,
|
|
303
|
+
*,
|
|
304
|
+
allow_missing: bool = False,
|
|
305
|
+
environment_name: typing.Optional[str] = None,
|
|
306
|
+
client: typing.Optional[modal.client.Client] = None,
|
|
307
|
+
):
|
|
308
|
+
"""Delete a named Secret.
|
|
309
|
+
|
|
310
|
+
Warning: Deletion is irreversible and will affect any Apps currently using the Secret.
|
|
311
|
+
|
|
312
|
+
**Examples:**
|
|
313
|
+
|
|
314
|
+
```python notest
|
|
315
|
+
await modal.Secret.objects.delete("my-secret")
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
Secrets will be deleted from the active environment, or another one can be specified:
|
|
319
|
+
|
|
320
|
+
```python notest
|
|
321
|
+
await modal.Secret.objects.delete("my-secret", environment_name="dev")
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
Added in v1.1.2.
|
|
325
|
+
"""
|
|
326
|
+
...
|
|
327
|
+
|
|
328
|
+
async def aio(
|
|
329
|
+
self,
|
|
330
|
+
/,
|
|
331
|
+
name: str,
|
|
332
|
+
*,
|
|
333
|
+
allow_missing: bool = False,
|
|
334
|
+
environment_name: typing.Optional[str] = None,
|
|
335
|
+
client: typing.Optional[modal.client.Client] = None,
|
|
336
|
+
):
|
|
337
|
+
"""Delete a named Secret.
|
|
338
|
+
|
|
339
|
+
Warning: Deletion is irreversible and will affect any Apps currently using the Secret.
|
|
340
|
+
|
|
341
|
+
**Examples:**
|
|
342
|
+
|
|
343
|
+
```python notest
|
|
344
|
+
await modal.Secret.objects.delete("my-secret")
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
Secrets will be deleted from the active environment, or another one can be specified:
|
|
348
|
+
|
|
349
|
+
```python notest
|
|
350
|
+
await modal.Secret.objects.delete("my-secret", environment_name="dev")
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
Added in v1.1.2.
|
|
354
|
+
"""
|
|
355
|
+
...
|
|
356
|
+
|
|
357
|
+
delete: __delete_spec
|
|
358
|
+
|
|
359
|
+
async def _load_from_env_dict(
|
|
360
|
+
instance: _Secret, load_context: modal._load_context.LoadContext, env_dict: dict[str, str]
|
|
361
|
+
):
|
|
362
|
+
"""helper method for loaders .from_dict and .from_dotenv etc."""
|
|
363
|
+
...
|
|
364
|
+
|
|
7
365
|
class _Secret(modal._object._Object):
|
|
8
366
|
"""Secrets provide a dictionary of environment variables for images.
|
|
9
367
|
|
|
@@ -13,6 +371,15 @@ class _Secret(modal._object._Object):
|
|
|
13
371
|
|
|
14
372
|
See [the secrets guide page](https://modal.com/docs/guide/secrets) for more information.
|
|
15
373
|
"""
|
|
374
|
+
|
|
375
|
+
_metadata: typing.Optional[modal_proto.api_pb2.SecretMetadata]
|
|
376
|
+
|
|
377
|
+
@synchronicity.classproperty
|
|
378
|
+
def objects(cls) -> _SecretManager: ...
|
|
379
|
+
@property
|
|
380
|
+
def name(self) -> typing.Optional[str]: ...
|
|
381
|
+
def _hydrate_metadata(self, metadata: typing.Optional[google.protobuf.message.Message]): ...
|
|
382
|
+
def _get_metadata(self) -> modal_proto.api_pb2.SecretMetadata: ...
|
|
16
383
|
@staticmethod
|
|
17
384
|
def from_dict(env_dict: dict[str, typing.Optional[str]] = {}) -> _Secret:
|
|
18
385
|
"""Create a secret from a str-str dictionary. Values can also be `None`, which is ignored.
|
|
@@ -32,7 +399,7 @@ class _Secret(modal._object._Object):
|
|
|
32
399
|
...
|
|
33
400
|
|
|
34
401
|
@staticmethod
|
|
35
|
-
def from_dotenv(path=None, *, filename=".env") -> _Secret:
|
|
402
|
+
def from_dotenv(path=None, *, filename=".env", client: typing.Optional[modal.client._Client] = None) -> _Secret:
|
|
36
403
|
"""Create secrets from a .env file automatically.
|
|
37
404
|
|
|
38
405
|
If no argument is provided, it will use the current working directory as the starting
|
|
@@ -63,7 +430,12 @@ class _Secret(modal._object._Object):
|
|
|
63
430
|
|
|
64
431
|
@staticmethod
|
|
65
432
|
def from_name(
|
|
66
|
-
name: str,
|
|
433
|
+
name: str,
|
|
434
|
+
*,
|
|
435
|
+
namespace=None,
|
|
436
|
+
environment_name: typing.Optional[str] = None,
|
|
437
|
+
required_keys: list[str] = [],
|
|
438
|
+
client: typing.Optional[modal.client._Client] = None,
|
|
67
439
|
) -> _Secret:
|
|
68
440
|
"""Reference a Secret by its name.
|
|
69
441
|
|
|
@@ -82,18 +454,19 @@ class _Secret(modal._object._Object):
|
|
|
82
454
|
...
|
|
83
455
|
|
|
84
456
|
@staticmethod
|
|
85
|
-
async def
|
|
86
|
-
|
|
457
|
+
async def create_deployed(
|
|
458
|
+
deployment_name: str,
|
|
459
|
+
env_dict: dict[str, str],
|
|
87
460
|
namespace=None,
|
|
88
461
|
client: typing.Optional[modal.client._Client] = None,
|
|
89
462
|
environment_name: typing.Optional[str] = None,
|
|
90
|
-
|
|
91
|
-
) ->
|
|
463
|
+
overwrite: bool = False,
|
|
464
|
+
) -> str:
|
|
92
465
|
"""mdmd:hidden"""
|
|
93
466
|
...
|
|
94
467
|
|
|
95
468
|
@staticmethod
|
|
96
|
-
async def
|
|
469
|
+
async def _create_deployed(
|
|
97
470
|
deployment_name: str,
|
|
98
471
|
env_dict: dict[str, str],
|
|
99
472
|
namespace=None,
|
|
@@ -104,6 +477,12 @@ class _Secret(modal._object._Object):
|
|
|
104
477
|
"""mdmd:hidden"""
|
|
105
478
|
...
|
|
106
479
|
|
|
480
|
+
async def info(self) -> SecretInfo:
|
|
481
|
+
"""Return information about the Secret object."""
|
|
482
|
+
...
|
|
483
|
+
|
|
484
|
+
SUPERSELF = typing.TypeVar("SUPERSELF", covariant=True)
|
|
485
|
+
|
|
107
486
|
class Secret(modal.object.Object):
|
|
108
487
|
"""Secrets provide a dictionary of environment variables for images.
|
|
109
488
|
|
|
@@ -113,10 +492,19 @@ class Secret(modal.object.Object):
|
|
|
113
492
|
|
|
114
493
|
See [the secrets guide page](https://modal.com/docs/guide/secrets) for more information.
|
|
115
494
|
"""
|
|
495
|
+
|
|
496
|
+
_metadata: typing.Optional[modal_proto.api_pb2.SecretMetadata]
|
|
497
|
+
|
|
116
498
|
def __init__(self, *args, **kwargs):
|
|
117
499
|
"""mdmd:hidden"""
|
|
118
500
|
...
|
|
119
501
|
|
|
502
|
+
@synchronicity.classproperty
|
|
503
|
+
def objects(cls) -> SecretManager: ...
|
|
504
|
+
@property
|
|
505
|
+
def name(self) -> typing.Optional[str]: ...
|
|
506
|
+
def _hydrate_metadata(self, metadata: typing.Optional[google.protobuf.message.Message]): ...
|
|
507
|
+
def _get_metadata(self) -> modal_proto.api_pb2.SecretMetadata: ...
|
|
120
508
|
@staticmethod
|
|
121
509
|
def from_dict(env_dict: dict[str, typing.Optional[str]] = {}) -> Secret:
|
|
122
510
|
"""Create a secret from a str-str dictionary. Values can also be `None`, which is ignored.
|
|
@@ -136,7 +524,7 @@ class Secret(modal.object.Object):
|
|
|
136
524
|
...
|
|
137
525
|
|
|
138
526
|
@staticmethod
|
|
139
|
-
def from_dotenv(path=None, *, filename=".env") -> Secret:
|
|
527
|
+
def from_dotenv(path=None, *, filename=".env", client: typing.Optional[modal.client.Client] = None) -> Secret:
|
|
140
528
|
"""Create secrets from a .env file automatically.
|
|
141
529
|
|
|
142
530
|
If no argument is provided, it will use the current working directory as the starting
|
|
@@ -167,7 +555,12 @@ class Secret(modal.object.Object):
|
|
|
167
555
|
|
|
168
556
|
@staticmethod
|
|
169
557
|
def from_name(
|
|
170
|
-
name: str,
|
|
558
|
+
name: str,
|
|
559
|
+
*,
|
|
560
|
+
namespace=None,
|
|
561
|
+
environment_name: typing.Optional[str] = None,
|
|
562
|
+
required_keys: list[str] = [],
|
|
563
|
+
client: typing.Optional[modal.client.Client] = None,
|
|
171
564
|
) -> Secret:
|
|
172
565
|
"""Reference a Secret by its name.
|
|
173
566
|
|
|
@@ -185,34 +578,36 @@ class Secret(modal.object.Object):
|
|
|
185
578
|
"""
|
|
186
579
|
...
|
|
187
580
|
|
|
188
|
-
class
|
|
581
|
+
class __create_deployed_spec(typing_extensions.Protocol):
|
|
189
582
|
def __call__(
|
|
190
583
|
self,
|
|
191
584
|
/,
|
|
192
|
-
|
|
585
|
+
deployment_name: str,
|
|
586
|
+
env_dict: dict[str, str],
|
|
193
587
|
namespace=None,
|
|
194
588
|
client: typing.Optional[modal.client.Client] = None,
|
|
195
589
|
environment_name: typing.Optional[str] = None,
|
|
196
|
-
|
|
197
|
-
) ->
|
|
590
|
+
overwrite: bool = False,
|
|
591
|
+
) -> str:
|
|
198
592
|
"""mdmd:hidden"""
|
|
199
593
|
...
|
|
200
594
|
|
|
201
595
|
async def aio(
|
|
202
596
|
self,
|
|
203
597
|
/,
|
|
204
|
-
|
|
598
|
+
deployment_name: str,
|
|
599
|
+
env_dict: dict[str, str],
|
|
205
600
|
namespace=None,
|
|
206
601
|
client: typing.Optional[modal.client.Client] = None,
|
|
207
602
|
environment_name: typing.Optional[str] = None,
|
|
208
|
-
|
|
209
|
-
) ->
|
|
603
|
+
overwrite: bool = False,
|
|
604
|
+
) -> str:
|
|
210
605
|
"""mdmd:hidden"""
|
|
211
606
|
...
|
|
212
607
|
|
|
213
|
-
|
|
608
|
+
create_deployed: __create_deployed_spec
|
|
214
609
|
|
|
215
|
-
class
|
|
610
|
+
class ___create_deployed_spec(typing_extensions.Protocol):
|
|
216
611
|
def __call__(
|
|
217
612
|
self,
|
|
218
613
|
/,
|
|
@@ -239,4 +634,15 @@ class Secret(modal.object.Object):
|
|
|
239
634
|
"""mdmd:hidden"""
|
|
240
635
|
...
|
|
241
636
|
|
|
242
|
-
|
|
637
|
+
_create_deployed: ___create_deployed_spec
|
|
638
|
+
|
|
639
|
+
class __info_spec(typing_extensions.Protocol[SUPERSELF]):
|
|
640
|
+
def __call__(self, /) -> SecretInfo:
|
|
641
|
+
"""Return information about the Secret object."""
|
|
642
|
+
...
|
|
643
|
+
|
|
644
|
+
async def aio(self, /) -> SecretInfo:
|
|
645
|
+
"""Return information about the Secret object."""
|
|
646
|
+
...
|
|
647
|
+
|
|
648
|
+
info: __info_spec[typing_extensions.Self]
|
modal/serving.py
CHANGED
|
@@ -4,13 +4,13 @@ import platform
|
|
|
4
4
|
from collections.abc import AsyncGenerator
|
|
5
5
|
from multiprocessing.context import SpawnProcess
|
|
6
6
|
from multiprocessing.synchronize import Event
|
|
7
|
-
from typing import TYPE_CHECKING, Optional
|
|
7
|
+
from typing import TYPE_CHECKING, Optional
|
|
8
8
|
|
|
9
9
|
from synchronicity.async_wrap import asynccontextmanager
|
|
10
10
|
|
|
11
11
|
from modal._output import OutputManager
|
|
12
12
|
|
|
13
|
-
from ._utils.async_utils import TaskContext, asyncify, synchronize_api
|
|
13
|
+
from ._utils.async_utils import TaskContext, asyncify, synchronize_api
|
|
14
14
|
from ._utils.logger import logger
|
|
15
15
|
from ._watcher import watch
|
|
16
16
|
from .cli.import_refs import ImportRef, import_app_from_ref
|
|
@@ -20,20 +20,16 @@ from .output import _get_output_manager, enable_output
|
|
|
20
20
|
from .runner import _run_app, serve_update
|
|
21
21
|
|
|
22
22
|
if TYPE_CHECKING:
|
|
23
|
-
|
|
24
|
-
else:
|
|
25
|
-
_App = TypeVar("_App")
|
|
23
|
+
import modal.app
|
|
26
24
|
|
|
27
25
|
|
|
28
26
|
def _run_serve(
|
|
29
27
|
import_ref: ImportRef, existing_app_id: str, is_ready: Event, environment_name: str, show_progress: bool
|
|
30
28
|
):
|
|
31
|
-
|
|
32
|
-
_app = import_app_from_ref(import_ref, base_cmd="modal serve")
|
|
33
|
-
blocking_app = synchronizer._translate_out(_app)
|
|
29
|
+
app = import_app_from_ref(import_ref, base_cmd="modal serve")
|
|
34
30
|
|
|
35
31
|
with enable_output(show_progress=show_progress):
|
|
36
|
-
serve_update(
|
|
32
|
+
serve_update(app, existing_app_id, is_ready, environment_name)
|
|
37
33
|
|
|
38
34
|
|
|
39
35
|
async def _restart_serve(
|
|
@@ -97,12 +93,12 @@ async def _run_watch_loop(
|
|
|
97
93
|
|
|
98
94
|
@asynccontextmanager
|
|
99
95
|
async def _serve_app(
|
|
100
|
-
app: "_App",
|
|
96
|
+
app: "modal.app._App",
|
|
101
97
|
import_ref: ImportRef,
|
|
102
98
|
*,
|
|
103
99
|
_watcher: Optional[AsyncGenerator[set[str], None]] = None, # for testing
|
|
104
100
|
environment_name: Optional[str] = None,
|
|
105
|
-
) -> AsyncGenerator["_App", None]:
|
|
101
|
+
) -> AsyncGenerator["modal.app._App", None]:
|
|
106
102
|
if environment_name is None:
|
|
107
103
|
environment_name = config.get("environment")
|
|
108
104
|
|
modal/serving.pyi
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import collections.abc
|
|
2
|
+
import modal.app
|
|
2
3
|
import modal.cli.import_refs
|
|
3
4
|
import multiprocessing.context
|
|
4
5
|
import multiprocessing.synchronize
|
|
@@ -6,8 +7,6 @@ import synchronicity.combined_types
|
|
|
6
7
|
import typing
|
|
7
8
|
import typing_extensions
|
|
8
9
|
|
|
9
|
-
_App = typing.TypeVar("_App")
|
|
10
|
-
|
|
11
10
|
def _run_serve(
|
|
12
11
|
import_ref: modal.cli.import_refs.ImportRef,
|
|
13
12
|
existing_app_id: str,
|
|
@@ -27,31 +26,31 @@ async def _run_watch_loop(
|
|
|
27
26
|
environment_name: str,
|
|
28
27
|
): ...
|
|
29
28
|
def _serve_app(
|
|
30
|
-
app: _App,
|
|
29
|
+
app: modal.app._App,
|
|
31
30
|
import_ref: modal.cli.import_refs.ImportRef,
|
|
32
31
|
*,
|
|
33
32
|
_watcher: typing.Optional[collections.abc.AsyncGenerator[set[str], None]] = None,
|
|
34
33
|
environment_name: typing.Optional[str] = None,
|
|
35
|
-
) -> typing.AsyncContextManager[_App]: ...
|
|
34
|
+
) -> typing.AsyncContextManager[modal.app._App]: ...
|
|
36
35
|
|
|
37
36
|
class __serve_app_spec(typing_extensions.Protocol):
|
|
38
37
|
def __call__(
|
|
39
38
|
self,
|
|
40
39
|
/,
|
|
41
|
-
app:
|
|
40
|
+
app: modal.app.App,
|
|
42
41
|
import_ref: modal.cli.import_refs.ImportRef,
|
|
43
42
|
*,
|
|
44
43
|
_watcher: typing.Optional[typing.Generator[set[str], None, None]] = None,
|
|
45
44
|
environment_name: typing.Optional[str] = None,
|
|
46
|
-
) -> synchronicity.combined_types.AsyncAndBlockingContextManager[
|
|
45
|
+
) -> synchronicity.combined_types.AsyncAndBlockingContextManager[modal.app.App]: ...
|
|
47
46
|
def aio(
|
|
48
47
|
self,
|
|
49
48
|
/,
|
|
50
|
-
app:
|
|
49
|
+
app: modal.app.App,
|
|
51
50
|
import_ref: modal.cli.import_refs.ImportRef,
|
|
52
51
|
*,
|
|
53
52
|
_watcher: typing.Optional[collections.abc.AsyncGenerator[set[str], None]] = None,
|
|
54
53
|
environment_name: typing.Optional[str] = None,
|
|
55
|
-
) -> typing.AsyncContextManager[
|
|
54
|
+
) -> typing.AsyncContextManager[modal.app.App]: ...
|
|
56
55
|
|
|
57
56
|
serve_app: __serve_app_spec
|
modal/snapshot.py
CHANGED
|
@@ -3,10 +3,10 @@ from typing import Optional
|
|
|
3
3
|
|
|
4
4
|
from modal_proto import api_pb2
|
|
5
5
|
|
|
6
|
+
from ._load_context import LoadContext
|
|
6
7
|
from ._object import _Object
|
|
7
8
|
from ._resolver import Resolver
|
|
8
9
|
from ._utils.async_utils import synchronize_api
|
|
9
|
-
from ._utils.grpc_utils import retry_transient_errors
|
|
10
10
|
from .client import _Client
|
|
11
11
|
|
|
12
12
|
|
|
@@ -24,16 +24,19 @@ class _SandboxSnapshot(_Object, type_prefix="sn"):
|
|
|
24
24
|
"""
|
|
25
25
|
Construct a `SandboxSnapshot` object from a sandbox snapshot ID.
|
|
26
26
|
"""
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
async def _load(
|
|
31
|
-
|
|
32
|
-
|
|
27
|
+
# TODO: remove this - from_id constructor should not do io:
|
|
28
|
+
client = client or await _Client.from_env()
|
|
29
|
+
|
|
30
|
+
async def _load(
|
|
31
|
+
self: _SandboxSnapshot, resolver: Resolver, load_context: LoadContext, existing_object_id: Optional[str]
|
|
32
|
+
):
|
|
33
|
+
await load_context.client.stub.SandboxSnapshotGet(
|
|
34
|
+
api_pb2.SandboxSnapshotGetRequest(snapshot_id=sandbox_snapshot_id)
|
|
33
35
|
)
|
|
34
36
|
|
|
35
37
|
rep = "SandboxSnapshot()"
|
|
36
|
-
obj = _SandboxSnapshot._from_loader(_load, rep)
|
|
38
|
+
obj = _SandboxSnapshot._from_loader(_load, rep, load_context_overrides=LoadContext(client=client))
|
|
39
|
+
# TODO: should this be a _Object._new_hydrated instead?
|
|
37
40
|
obj._hydrate(sandbox_snapshot_id, client, None)
|
|
38
41
|
|
|
39
42
|
return obj
|