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/mount.pyi
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import collections.abc
|
|
2
2
|
import google.protobuf.message
|
|
3
|
+
import modal._load_context
|
|
3
4
|
import modal._object
|
|
4
5
|
import modal._resolver
|
|
5
6
|
import modal._utils.blob_utils
|
|
@@ -154,7 +155,6 @@ class _Mount(modal._object._Object):
|
|
|
154
155
|
_entries: typing.Optional[list[_MountEntry]]
|
|
155
156
|
_deployment_name: typing.Optional[str]
|
|
156
157
|
_namespace: typing.Optional[int]
|
|
157
|
-
_environment_name: typing.Optional[str]
|
|
158
158
|
_allow_overwrite: bool
|
|
159
159
|
_content_checksum_sha256_hex: typing.Optional[str]
|
|
160
160
|
|
|
@@ -189,30 +189,6 @@ class _Mount(modal._object._Object):
|
|
|
189
189
|
"""Add a local directory to the `Mount` object."""
|
|
190
190
|
...
|
|
191
191
|
|
|
192
|
-
@staticmethod
|
|
193
|
-
def from_local_dir(
|
|
194
|
-
local_path: typing.Union[str, pathlib.Path],
|
|
195
|
-
*,
|
|
196
|
-
remote_path: typing.Union[str, pathlib.PurePosixPath, None] = None,
|
|
197
|
-
condition: typing.Optional[collections.abc.Callable[[str], bool]] = None,
|
|
198
|
-
recursive: bool = True,
|
|
199
|
-
) -> _Mount:
|
|
200
|
-
"""**Deprecated:** Use image.add_local_dir() instead
|
|
201
|
-
|
|
202
|
-
Create a `Mount` from a local directory.
|
|
203
|
-
|
|
204
|
-
**Usage**
|
|
205
|
-
|
|
206
|
-
```python notest
|
|
207
|
-
assets = modal.Mount.from_local_dir(
|
|
208
|
-
"~/assets",
|
|
209
|
-
condition=lambda pth: not ".venv" in pth,
|
|
210
|
-
remote_path="/assets",
|
|
211
|
-
)
|
|
212
|
-
```
|
|
213
|
-
"""
|
|
214
|
-
...
|
|
215
|
-
|
|
216
192
|
@staticmethod
|
|
217
193
|
def _from_local_dir(
|
|
218
194
|
local_path: typing.Union[str, pathlib.Path],
|
|
@@ -229,26 +205,6 @@ class _Mount(modal._object._Object):
|
|
|
229
205
|
"""Add a local file to the `Mount` object."""
|
|
230
206
|
...
|
|
231
207
|
|
|
232
|
-
@staticmethod
|
|
233
|
-
def from_local_file(
|
|
234
|
-
local_path: typing.Union[str, pathlib.Path], remote_path: typing.Union[str, pathlib.PurePosixPath, None] = None
|
|
235
|
-
) -> _Mount:
|
|
236
|
-
"""**Deprecated**: Use image.add_local_file() instead
|
|
237
|
-
|
|
238
|
-
Create a `Mount` mounting a single local file.
|
|
239
|
-
|
|
240
|
-
**Usage**
|
|
241
|
-
|
|
242
|
-
```python notest
|
|
243
|
-
# Mount the DBT profile in user's home directory into container.
|
|
244
|
-
dbt_profiles = modal.Mount.from_local_file(
|
|
245
|
-
local_path="~/profiles.yml",
|
|
246
|
-
remote_path="/root/dbt_profile/profiles.yml",
|
|
247
|
-
)
|
|
248
|
-
```
|
|
249
|
-
"""
|
|
250
|
-
...
|
|
251
|
-
|
|
252
208
|
@staticmethod
|
|
253
209
|
def _from_local_file(
|
|
254
210
|
local_path: typing.Union[str, pathlib.Path], remote_path: typing.Union[str, pathlib.PurePosixPath, None] = None
|
|
@@ -260,38 +216,11 @@ class _Mount(modal._object._Object):
|
|
|
260
216
|
entries: list[_MountEntry],
|
|
261
217
|
) -> collections.abc.AsyncGenerator[modal._utils.blob_utils.FileUploadSpec, None]: ...
|
|
262
218
|
async def _load_mount(
|
|
263
|
-
self: _Mount,
|
|
219
|
+
self: _Mount,
|
|
220
|
+
resolver: modal._resolver.Resolver,
|
|
221
|
+
load_context: modal._load_context.LoadContext,
|
|
222
|
+
existing_object_id: typing.Optional[str],
|
|
264
223
|
): ...
|
|
265
|
-
@staticmethod
|
|
266
|
-
def from_local_python_packages(
|
|
267
|
-
*module_names: str,
|
|
268
|
-
remote_dir: typing.Union[str, pathlib.PurePosixPath] = "/root",
|
|
269
|
-
condition: typing.Optional[collections.abc.Callable[[str], bool]] = None,
|
|
270
|
-
ignore: typing.Union[typing.Sequence[str], collections.abc.Callable[[pathlib.Path], bool], None] = None,
|
|
271
|
-
) -> _Mount:
|
|
272
|
-
"""**Deprecated**: Use image.add_local_python_source instead
|
|
273
|
-
|
|
274
|
-
Returns a `modal.Mount` that makes local modules listed in `module_names` available inside the container.
|
|
275
|
-
This works by mounting the local path of each module's package to a directory inside the container
|
|
276
|
-
that's on `PYTHONPATH`.
|
|
277
|
-
|
|
278
|
-
**Usage**
|
|
279
|
-
|
|
280
|
-
```python notest
|
|
281
|
-
import modal
|
|
282
|
-
import my_local_module
|
|
283
|
-
|
|
284
|
-
app = modal.App()
|
|
285
|
-
|
|
286
|
-
@app.function(mounts=[
|
|
287
|
-
modal.Mount.from_local_python_packages("my_local_module", "my_other_module"),
|
|
288
|
-
])
|
|
289
|
-
def f():
|
|
290
|
-
my_local_module.do_stuff()
|
|
291
|
-
```
|
|
292
|
-
"""
|
|
293
|
-
...
|
|
294
|
-
|
|
295
224
|
@staticmethod
|
|
296
225
|
def _from_local_python_packages(
|
|
297
226
|
*module_names: str,
|
|
@@ -300,17 +229,12 @@ class _Mount(modal._object._Object):
|
|
|
300
229
|
ignore: typing.Union[typing.Sequence[str], collections.abc.Callable[[pathlib.Path], bool], None] = None,
|
|
301
230
|
) -> _Mount: ...
|
|
302
231
|
@staticmethod
|
|
303
|
-
def from_name(
|
|
304
|
-
"""mdmd:hidden"""
|
|
305
|
-
...
|
|
306
|
-
|
|
307
|
-
@classmethod
|
|
308
|
-
async def lookup(
|
|
309
|
-
cls: type[_Mount],
|
|
232
|
+
def from_name(
|
|
310
233
|
name: str,
|
|
234
|
+
*,
|
|
311
235
|
namespace=1,
|
|
312
|
-
client: typing.Optional[modal.client._Client] = None,
|
|
313
236
|
environment_name: typing.Optional[str] = None,
|
|
237
|
+
client: typing.Optional[modal.client._Client] = None,
|
|
314
238
|
) -> _Mount:
|
|
315
239
|
"""mdmd:hidden"""
|
|
316
240
|
...
|
|
@@ -354,7 +278,6 @@ class Mount(modal.object.Object):
|
|
|
354
278
|
_entries: typing.Optional[list[_MountEntry]]
|
|
355
279
|
_deployment_name: typing.Optional[str]
|
|
356
280
|
_namespace: typing.Optional[int]
|
|
357
|
-
_environment_name: typing.Optional[str]
|
|
358
281
|
_allow_overwrite: bool
|
|
359
282
|
_content_checksum_sha256_hex: typing.Optional[str]
|
|
360
283
|
|
|
@@ -393,30 +316,6 @@ class Mount(modal.object.Object):
|
|
|
393
316
|
"""Add a local directory to the `Mount` object."""
|
|
394
317
|
...
|
|
395
318
|
|
|
396
|
-
@staticmethod
|
|
397
|
-
def from_local_dir(
|
|
398
|
-
local_path: typing.Union[str, pathlib.Path],
|
|
399
|
-
*,
|
|
400
|
-
remote_path: typing.Union[str, pathlib.PurePosixPath, None] = None,
|
|
401
|
-
condition: typing.Optional[collections.abc.Callable[[str], bool]] = None,
|
|
402
|
-
recursive: bool = True,
|
|
403
|
-
) -> Mount:
|
|
404
|
-
"""**Deprecated:** Use image.add_local_dir() instead
|
|
405
|
-
|
|
406
|
-
Create a `Mount` from a local directory.
|
|
407
|
-
|
|
408
|
-
**Usage**
|
|
409
|
-
|
|
410
|
-
```python notest
|
|
411
|
-
assets = modal.Mount.from_local_dir(
|
|
412
|
-
"~/assets",
|
|
413
|
-
condition=lambda pth: not ".venv" in pth,
|
|
414
|
-
remote_path="/assets",
|
|
415
|
-
)
|
|
416
|
-
```
|
|
417
|
-
"""
|
|
418
|
-
...
|
|
419
|
-
|
|
420
319
|
@staticmethod
|
|
421
320
|
def _from_local_dir(
|
|
422
321
|
local_path: typing.Union[str, pathlib.Path],
|
|
@@ -433,26 +332,6 @@ class Mount(modal.object.Object):
|
|
|
433
332
|
"""Add a local file to the `Mount` object."""
|
|
434
333
|
...
|
|
435
334
|
|
|
436
|
-
@staticmethod
|
|
437
|
-
def from_local_file(
|
|
438
|
-
local_path: typing.Union[str, pathlib.Path], remote_path: typing.Union[str, pathlib.PurePosixPath, None] = None
|
|
439
|
-
) -> Mount:
|
|
440
|
-
"""**Deprecated**: Use image.add_local_file() instead
|
|
441
|
-
|
|
442
|
-
Create a `Mount` mounting a single local file.
|
|
443
|
-
|
|
444
|
-
**Usage**
|
|
445
|
-
|
|
446
|
-
```python notest
|
|
447
|
-
# Mount the DBT profile in user's home directory into container.
|
|
448
|
-
dbt_profiles = modal.Mount.from_local_file(
|
|
449
|
-
local_path="~/profiles.yml",
|
|
450
|
-
remote_path="/root/dbt_profile/profiles.yml",
|
|
451
|
-
)
|
|
452
|
-
```
|
|
453
|
-
"""
|
|
454
|
-
...
|
|
455
|
-
|
|
456
335
|
@staticmethod
|
|
457
336
|
def _from_local_file(
|
|
458
337
|
local_path: typing.Union[str, pathlib.Path], remote_path: typing.Union[str, pathlib.PurePosixPath, None] = None
|
|
@@ -471,41 +350,23 @@ class Mount(modal.object.Object):
|
|
|
471
350
|
_get_files: ___get_files_spec
|
|
472
351
|
|
|
473
352
|
class ___load_mount_spec(typing_extensions.Protocol[SUPERSELF]):
|
|
474
|
-
def __call__(
|
|
475
|
-
|
|
353
|
+
def __call__(
|
|
354
|
+
self,
|
|
355
|
+
/,
|
|
356
|
+
resolver: modal._resolver.Resolver,
|
|
357
|
+
load_context: modal._load_context.LoadContext,
|
|
358
|
+
existing_object_id: typing.Optional[str],
|
|
359
|
+
): ...
|
|
360
|
+
async def aio(
|
|
361
|
+
self,
|
|
362
|
+
/,
|
|
363
|
+
resolver: modal._resolver.Resolver,
|
|
364
|
+
load_context: modal._load_context.LoadContext,
|
|
365
|
+
existing_object_id: typing.Optional[str],
|
|
366
|
+
): ...
|
|
476
367
|
|
|
477
368
|
_load_mount: ___load_mount_spec[typing_extensions.Self]
|
|
478
369
|
|
|
479
|
-
@staticmethod
|
|
480
|
-
def from_local_python_packages(
|
|
481
|
-
*module_names: str,
|
|
482
|
-
remote_dir: typing.Union[str, pathlib.PurePosixPath] = "/root",
|
|
483
|
-
condition: typing.Optional[collections.abc.Callable[[str], bool]] = None,
|
|
484
|
-
ignore: typing.Union[typing.Sequence[str], collections.abc.Callable[[pathlib.Path], bool], None] = None,
|
|
485
|
-
) -> Mount:
|
|
486
|
-
"""**Deprecated**: Use image.add_local_python_source instead
|
|
487
|
-
|
|
488
|
-
Returns a `modal.Mount` that makes local modules listed in `module_names` available inside the container.
|
|
489
|
-
This works by mounting the local path of each module's package to a directory inside the container
|
|
490
|
-
that's on `PYTHONPATH`.
|
|
491
|
-
|
|
492
|
-
**Usage**
|
|
493
|
-
|
|
494
|
-
```python notest
|
|
495
|
-
import modal
|
|
496
|
-
import my_local_module
|
|
497
|
-
|
|
498
|
-
app = modal.App()
|
|
499
|
-
|
|
500
|
-
@app.function(mounts=[
|
|
501
|
-
modal.Mount.from_local_python_packages("my_local_module", "my_other_module"),
|
|
502
|
-
])
|
|
503
|
-
def f():
|
|
504
|
-
my_local_module.do_stuff()
|
|
505
|
-
```
|
|
506
|
-
"""
|
|
507
|
-
...
|
|
508
|
-
|
|
509
370
|
@staticmethod
|
|
510
371
|
def _from_local_python_packages(
|
|
511
372
|
*module_names: str,
|
|
@@ -514,17 +375,12 @@ class Mount(modal.object.Object):
|
|
|
514
375
|
ignore: typing.Union[typing.Sequence[str], collections.abc.Callable[[pathlib.Path], bool], None] = None,
|
|
515
376
|
) -> Mount: ...
|
|
516
377
|
@staticmethod
|
|
517
|
-
def from_name(
|
|
518
|
-
"""mdmd:hidden"""
|
|
519
|
-
...
|
|
520
|
-
|
|
521
|
-
@classmethod
|
|
522
|
-
def lookup(
|
|
523
|
-
cls: type[Mount],
|
|
378
|
+
def from_name(
|
|
524
379
|
name: str,
|
|
380
|
+
*,
|
|
525
381
|
namespace=1,
|
|
526
|
-
client: typing.Optional[modal.client.Client] = None,
|
|
527
382
|
environment_name: typing.Optional[str] = None,
|
|
383
|
+
client: typing.Optional[modal.client.Client] = None,
|
|
528
384
|
) -> Mount:
|
|
529
385
|
"""mdmd:hidden"""
|
|
530
386
|
...
|
|
@@ -568,17 +424,34 @@ async def _create_single_client_dependency_mount(
|
|
|
568
424
|
uv_python_platform: str,
|
|
569
425
|
check_if_exists: bool = True,
|
|
570
426
|
allow_overwrite: bool = False,
|
|
427
|
+
dry_run: bool = False,
|
|
571
428
|
): ...
|
|
572
429
|
async def _create_client_dependency_mounts(
|
|
573
|
-
client=None,
|
|
430
|
+
client=None,
|
|
431
|
+
python_versions: list[str] = ["3.9", "3.10", "3.11", "3.12", "3.13"],
|
|
432
|
+
builder_versions: list[str] = ["2025.06"],
|
|
433
|
+
check_if_exists=True,
|
|
434
|
+
dry_run=False,
|
|
574
435
|
): ...
|
|
575
436
|
|
|
576
437
|
class __create_client_dependency_mounts_spec(typing_extensions.Protocol):
|
|
577
438
|
def __call__(
|
|
578
|
-
self,
|
|
439
|
+
self,
|
|
440
|
+
/,
|
|
441
|
+
client=None,
|
|
442
|
+
python_versions: list[str] = ["3.9", "3.10", "3.11", "3.12", "3.13"],
|
|
443
|
+
builder_versions: list[str] = ["2025.06"],
|
|
444
|
+
check_if_exists=True,
|
|
445
|
+
dry_run=False,
|
|
579
446
|
): ...
|
|
580
447
|
async def aio(
|
|
581
|
-
self,
|
|
448
|
+
self,
|
|
449
|
+
/,
|
|
450
|
+
client=None,
|
|
451
|
+
python_versions: list[str] = ["3.9", "3.10", "3.11", "3.12", "3.13"],
|
|
452
|
+
builder_versions: list[str] = ["2025.06"],
|
|
453
|
+
check_if_exists=True,
|
|
454
|
+
dry_run=False,
|
|
582
455
|
): ...
|
|
583
456
|
|
|
584
457
|
create_client_dependency_mounts: __create_client_dependency_mounts_spec
|
modal/network_file_system.py
CHANGED
|
@@ -11,6 +11,7 @@ from synchronicity.async_wrap import asynccontextmanager
|
|
|
11
11
|
import modal
|
|
12
12
|
from modal_proto import api_pb2
|
|
13
13
|
|
|
14
|
+
from ._load_context import LoadContext
|
|
14
15
|
from ._object import (
|
|
15
16
|
EPHEMERAL_OBJECT_HEARTBEAT_SLEEP,
|
|
16
17
|
_get_environment_name,
|
|
@@ -21,8 +22,7 @@ from ._object import (
|
|
|
21
22
|
from ._resolver import Resolver
|
|
22
23
|
from ._utils.async_utils import TaskContext, aclosing, async_map, sync_or_async_iter, synchronize_api
|
|
23
24
|
from ._utils.blob_utils import LARGE_FILE_LIMIT, blob_iter, blob_upload_file
|
|
24
|
-
from ._utils.deprecation import
|
|
25
|
-
from ._utils.grpc_utils import retry_transient_errors
|
|
25
|
+
from ._utils.deprecation import warn_if_passing_namespace
|
|
26
26
|
from ._utils.hash_utils import get_sha256_hex
|
|
27
27
|
from ._utils.name_utils import check_object_name
|
|
28
28
|
from .client import _Client
|
|
@@ -55,6 +55,8 @@ class _NetworkFileSystem(_Object, type_prefix="sv"):
|
|
|
55
55
|
By attaching this file system as a mount to one or more functions, they can
|
|
56
56
|
share and persist data with each other.
|
|
57
57
|
|
|
58
|
+
**Note: `NetworkFileSystem` has been deprecated and will be removed.**
|
|
59
|
+
|
|
58
60
|
**Usage**
|
|
59
61
|
|
|
60
62
|
```python
|
|
@@ -94,6 +96,7 @@ class _NetworkFileSystem(_Object, type_prefix="sv"):
|
|
|
94
96
|
namespace=None, # mdmd:line-hidden
|
|
95
97
|
environment_name: Optional[str] = None,
|
|
96
98
|
create_if_missing: bool = False,
|
|
99
|
+
client: Optional[_Client] = None,
|
|
97
100
|
) -> "_NetworkFileSystem":
|
|
98
101
|
"""Reference a NetworkFileSystem by its name, creating if necessary.
|
|
99
102
|
|
|
@@ -112,15 +115,17 @@ class _NetworkFileSystem(_Object, type_prefix="sv"):
|
|
|
112
115
|
check_object_name(name, "NetworkFileSystem")
|
|
113
116
|
warn_if_passing_namespace(namespace, "modal.NetworkFileSystem.from_name")
|
|
114
117
|
|
|
115
|
-
async def _load(
|
|
118
|
+
async def _load(
|
|
119
|
+
self: _NetworkFileSystem, resolver: Resolver, load_context: LoadContext, existing_object_id: Optional[str]
|
|
120
|
+
):
|
|
116
121
|
req = api_pb2.SharedVolumeGetOrCreateRequest(
|
|
117
122
|
deployment_name=name,
|
|
118
|
-
environment_name=
|
|
123
|
+
environment_name=load_context.environment_name,
|
|
119
124
|
object_creation_type=(api_pb2.OBJECT_CREATION_TYPE_CREATE_IF_MISSING if create_if_missing else None),
|
|
120
125
|
)
|
|
121
126
|
try:
|
|
122
|
-
response = await
|
|
123
|
-
self._hydrate(response.shared_volume_id,
|
|
127
|
+
response = await load_context.client.stub.SharedVolumeGetOrCreate(req)
|
|
128
|
+
self._hydrate(response.shared_volume_id, load_context.client, None)
|
|
124
129
|
except modal.exception.NotFoundError as exc:
|
|
125
130
|
if exc.args[0] == "App has wrong entity vo":
|
|
126
131
|
raise InvalidError(
|
|
@@ -128,7 +133,12 @@ class _NetworkFileSystem(_Object, type_prefix="sv"):
|
|
|
128
133
|
)
|
|
129
134
|
raise
|
|
130
135
|
|
|
131
|
-
return _NetworkFileSystem._from_loader(
|
|
136
|
+
return _NetworkFileSystem._from_loader(
|
|
137
|
+
_load,
|
|
138
|
+
"NetworkFileSystem()",
|
|
139
|
+
hydrate_lazily=True,
|
|
140
|
+
load_context_overrides=LoadContext(environment_name=environment_name, client=client),
|
|
141
|
+
)
|
|
132
142
|
|
|
133
143
|
@classmethod
|
|
134
144
|
@asynccontextmanager
|
|
@@ -136,7 +146,7 @@ class _NetworkFileSystem(_Object, type_prefix="sv"):
|
|
|
136
146
|
cls: type["_NetworkFileSystem"],
|
|
137
147
|
client: Optional[_Client] = None,
|
|
138
148
|
environment_name: Optional[str] = None,
|
|
139
|
-
_heartbeat_sleep: float = EPHEMERAL_OBJECT_HEARTBEAT_SLEEP,
|
|
149
|
+
_heartbeat_sleep: float = EPHEMERAL_OBJECT_HEARTBEAT_SLEEP, # mdmd:line-hidden
|
|
140
150
|
) -> AsyncIterator["_NetworkFileSystem"]:
|
|
141
151
|
"""Creates a new ephemeral network filesystem within a context manager:
|
|
142
152
|
|
|
@@ -161,46 +171,13 @@ class _NetworkFileSystem(_Object, type_prefix="sv"):
|
|
|
161
171
|
async with TaskContext() as tc:
|
|
162
172
|
request = api_pb2.SharedVolumeHeartbeatRequest(shared_volume_id=response.shared_volume_id)
|
|
163
173
|
tc.infinite_loop(lambda: client.stub.SharedVolumeHeartbeat(request), sleep=_heartbeat_sleep)
|
|
164
|
-
yield cls._new_hydrated(
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
environment_name: Optional[str] = None,
|
|
172
|
-
create_if_missing: bool = False,
|
|
173
|
-
) -> "_NetworkFileSystem":
|
|
174
|
-
"""mdmd:hidden
|
|
175
|
-
Lookup a named NetworkFileSystem.
|
|
176
|
-
|
|
177
|
-
DEPRECATED: This method is deprecated in favor of `modal.NetworkFileSystem.from_name`.
|
|
178
|
-
|
|
179
|
-
In contrast to `modal.NetworkFileSystem.from_name`, this is an eager method
|
|
180
|
-
that will hydrate the local object with metadata from Modal servers.
|
|
181
|
-
|
|
182
|
-
```python notest
|
|
183
|
-
nfs = modal.NetworkFileSystem.lookup("my-nfs")
|
|
184
|
-
print(nfs.listdir("/"))
|
|
185
|
-
```
|
|
186
|
-
"""
|
|
187
|
-
deprecation_warning(
|
|
188
|
-
(2025, 1, 27),
|
|
189
|
-
"`modal.NetworkFileSystem.lookup` is deprecated and will be removed in a future release."
|
|
190
|
-
" It can be replaced with `modal.NetworkFileSystem.from_name`."
|
|
191
|
-
"\n\nSee https://modal.com/docs/guide/modal-1-0-migration for more information.",
|
|
192
|
-
)
|
|
193
|
-
warn_if_passing_namespace(namespace, "modal.NetworkFileSystem.lookup")
|
|
194
|
-
obj = _NetworkFileSystem.from_name(
|
|
195
|
-
name,
|
|
196
|
-
environment_name=environment_name,
|
|
197
|
-
create_if_missing=create_if_missing,
|
|
198
|
-
)
|
|
199
|
-
if client is None:
|
|
200
|
-
client = await _Client.from_env()
|
|
201
|
-
resolver = Resolver(client=client)
|
|
202
|
-
await resolver.load(obj)
|
|
203
|
-
return obj
|
|
174
|
+
yield cls._new_hydrated(
|
|
175
|
+
response.shared_volume_id,
|
|
176
|
+
client,
|
|
177
|
+
None,
|
|
178
|
+
is_another_app=True,
|
|
179
|
+
rep="modal.NetworkFileSystem.ephemeral()",
|
|
180
|
+
)
|
|
204
181
|
|
|
205
182
|
@staticmethod
|
|
206
183
|
async def create_deployed(
|
|
@@ -219,14 +196,14 @@ class _NetworkFileSystem(_Object, type_prefix="sv"):
|
|
|
219
196
|
environment_name=_get_environment_name(environment_name),
|
|
220
197
|
object_creation_type=api_pb2.OBJECT_CREATION_TYPE_CREATE_FAIL_IF_EXISTS,
|
|
221
198
|
)
|
|
222
|
-
resp = await
|
|
199
|
+
resp = await client.stub.SharedVolumeGetOrCreate(request)
|
|
223
200
|
return resp.shared_volume_id
|
|
224
201
|
|
|
225
202
|
@staticmethod
|
|
226
203
|
async def delete(name: str, client: Optional[_Client] = None, environment_name: Optional[str] = None):
|
|
227
204
|
obj = await _NetworkFileSystem.from_name(name, environment_name=environment_name).hydrate(client)
|
|
228
205
|
req = api_pb2.SharedVolumeDeleteRequest(shared_volume_id=obj.object_id)
|
|
229
|
-
await
|
|
206
|
+
await obj._client.stub.SharedVolumeDelete(req)
|
|
230
207
|
|
|
231
208
|
@live_method
|
|
232
209
|
async def write_file(self, remote_path: str, fp: BinaryIO, progress_cb: Optional[Callable[..., Any]] = None) -> int:
|
|
@@ -266,7 +243,7 @@ class _NetworkFileSystem(_Object, type_prefix="sv"):
|
|
|
266
243
|
|
|
267
244
|
t0 = time.monotonic()
|
|
268
245
|
while time.monotonic() - t0 < NETWORK_FILE_SYSTEM_PUT_FILE_CLIENT_TIMEOUT:
|
|
269
|
-
response = await
|
|
246
|
+
response = await self._client.stub.SharedVolumePutFile(req)
|
|
270
247
|
if response.exists:
|
|
271
248
|
break
|
|
272
249
|
else:
|
|
@@ -279,7 +256,7 @@ class _NetworkFileSystem(_Object, type_prefix="sv"):
|
|
|
279
256
|
"""Read a file from the network file system"""
|
|
280
257
|
req = api_pb2.SharedVolumeGetFileRequest(shared_volume_id=self.object_id, path=path)
|
|
281
258
|
try:
|
|
282
|
-
response = await
|
|
259
|
+
response = await self._client.stub.SharedVolumeGetFile(req)
|
|
283
260
|
except modal.exception.NotFoundError as exc:
|
|
284
261
|
raise FileNotFoundError(exc.args[0])
|
|
285
262
|
|
|
@@ -364,7 +341,7 @@ class _NetworkFileSystem(_Object, type_prefix="sv"):
|
|
|
364
341
|
"""Remove a file in a network file system."""
|
|
365
342
|
req = api_pb2.SharedVolumeRemoveFileRequest(shared_volume_id=self.object_id, path=path, recursive=recursive)
|
|
366
343
|
try:
|
|
367
|
-
await
|
|
344
|
+
await self._client.stub.SharedVolumeRemoveFile(req)
|
|
368
345
|
except modal.exception.NotFoundError as exc:
|
|
369
346
|
raise FileNotFoundError(exc.args[0])
|
|
370
347
|
|
modal/network_file_system.pyi
CHANGED
|
@@ -19,6 +19,8 @@ class _NetworkFileSystem(modal._object._Object):
|
|
|
19
19
|
By attaching this file system as a mount to one or more functions, they can
|
|
20
20
|
share and persist data with each other.
|
|
21
21
|
|
|
22
|
+
**Note: `NetworkFileSystem` has been deprecated and will be removed.**
|
|
23
|
+
|
|
22
24
|
**Usage**
|
|
23
25
|
|
|
24
26
|
```python
|
|
@@ -52,7 +54,12 @@ class _NetworkFileSystem(modal._object._Object):
|
|
|
52
54
|
"""
|
|
53
55
|
@staticmethod
|
|
54
56
|
def from_name(
|
|
55
|
-
name: str,
|
|
57
|
+
name: str,
|
|
58
|
+
*,
|
|
59
|
+
namespace=None,
|
|
60
|
+
environment_name: typing.Optional[str] = None,
|
|
61
|
+
create_if_missing: bool = False,
|
|
62
|
+
client: typing.Optional[modal.client._Client] = None,
|
|
56
63
|
) -> _NetworkFileSystem:
|
|
57
64
|
"""Reference a NetworkFileSystem by its name, creating if necessary.
|
|
58
65
|
|
|
@@ -92,29 +99,6 @@ class _NetworkFileSystem(modal._object._Object):
|
|
|
92
99
|
"""
|
|
93
100
|
...
|
|
94
101
|
|
|
95
|
-
@staticmethod
|
|
96
|
-
async def lookup(
|
|
97
|
-
name: str,
|
|
98
|
-
namespace=None,
|
|
99
|
-
client: typing.Optional[modal.client._Client] = None,
|
|
100
|
-
environment_name: typing.Optional[str] = None,
|
|
101
|
-
create_if_missing: bool = False,
|
|
102
|
-
) -> _NetworkFileSystem:
|
|
103
|
-
"""mdmd:hidden
|
|
104
|
-
Lookup a named NetworkFileSystem.
|
|
105
|
-
|
|
106
|
-
DEPRECATED: This method is deprecated in favor of `modal.NetworkFileSystem.from_name`.
|
|
107
|
-
|
|
108
|
-
In contrast to `modal.NetworkFileSystem.from_name`, this is an eager method
|
|
109
|
-
that will hydrate the local object with metadata from Modal servers.
|
|
110
|
-
|
|
111
|
-
```python notest
|
|
112
|
-
nfs = modal.NetworkFileSystem.lookup("my-nfs")
|
|
113
|
-
print(nfs.listdir("/"))
|
|
114
|
-
```
|
|
115
|
-
"""
|
|
116
|
-
...
|
|
117
|
-
|
|
118
102
|
@staticmethod
|
|
119
103
|
async def create_deployed(
|
|
120
104
|
deployment_name: str,
|
|
@@ -192,6 +176,8 @@ class NetworkFileSystem(modal.object.Object):
|
|
|
192
176
|
By attaching this file system as a mount to one or more functions, they can
|
|
193
177
|
share and persist data with each other.
|
|
194
178
|
|
|
179
|
+
**Note: `NetworkFileSystem` has been deprecated and will be removed.**
|
|
180
|
+
|
|
195
181
|
**Usage**
|
|
196
182
|
|
|
197
183
|
```python
|
|
@@ -229,7 +215,12 @@ class NetworkFileSystem(modal.object.Object):
|
|
|
229
215
|
|
|
230
216
|
@staticmethod
|
|
231
217
|
def from_name(
|
|
232
|
-
name: str,
|
|
218
|
+
name: str,
|
|
219
|
+
*,
|
|
220
|
+
namespace=None,
|
|
221
|
+
environment_name: typing.Optional[str] = None,
|
|
222
|
+
create_if_missing: bool = False,
|
|
223
|
+
client: typing.Optional[modal.client.Client] = None,
|
|
233
224
|
) -> NetworkFileSystem:
|
|
234
225
|
"""Reference a NetworkFileSystem by its name, creating if necessary.
|
|
235
226
|
|
|
@@ -269,57 +260,6 @@ class NetworkFileSystem(modal.object.Object):
|
|
|
269
260
|
"""
|
|
270
261
|
...
|
|
271
262
|
|
|
272
|
-
class __lookup_spec(typing_extensions.Protocol):
|
|
273
|
-
def __call__(
|
|
274
|
-
self,
|
|
275
|
-
/,
|
|
276
|
-
name: str,
|
|
277
|
-
namespace=None,
|
|
278
|
-
client: typing.Optional[modal.client.Client] = None,
|
|
279
|
-
environment_name: typing.Optional[str] = None,
|
|
280
|
-
create_if_missing: bool = False,
|
|
281
|
-
) -> NetworkFileSystem:
|
|
282
|
-
"""mdmd:hidden
|
|
283
|
-
Lookup a named NetworkFileSystem.
|
|
284
|
-
|
|
285
|
-
DEPRECATED: This method is deprecated in favor of `modal.NetworkFileSystem.from_name`.
|
|
286
|
-
|
|
287
|
-
In contrast to `modal.NetworkFileSystem.from_name`, this is an eager method
|
|
288
|
-
that will hydrate the local object with metadata from Modal servers.
|
|
289
|
-
|
|
290
|
-
```python notest
|
|
291
|
-
nfs = modal.NetworkFileSystem.lookup("my-nfs")
|
|
292
|
-
print(nfs.listdir("/"))
|
|
293
|
-
```
|
|
294
|
-
"""
|
|
295
|
-
...
|
|
296
|
-
|
|
297
|
-
async def aio(
|
|
298
|
-
self,
|
|
299
|
-
/,
|
|
300
|
-
name: str,
|
|
301
|
-
namespace=None,
|
|
302
|
-
client: typing.Optional[modal.client.Client] = None,
|
|
303
|
-
environment_name: typing.Optional[str] = None,
|
|
304
|
-
create_if_missing: bool = False,
|
|
305
|
-
) -> NetworkFileSystem:
|
|
306
|
-
"""mdmd:hidden
|
|
307
|
-
Lookup a named NetworkFileSystem.
|
|
308
|
-
|
|
309
|
-
DEPRECATED: This method is deprecated in favor of `modal.NetworkFileSystem.from_name`.
|
|
310
|
-
|
|
311
|
-
In contrast to `modal.NetworkFileSystem.from_name`, this is an eager method
|
|
312
|
-
that will hydrate the local object with metadata from Modal servers.
|
|
313
|
-
|
|
314
|
-
```python notest
|
|
315
|
-
nfs = modal.NetworkFileSystem.lookup("my-nfs")
|
|
316
|
-
print(nfs.listdir("/"))
|
|
317
|
-
```
|
|
318
|
-
"""
|
|
319
|
-
...
|
|
320
|
-
|
|
321
|
-
lookup: __lookup_spec
|
|
322
|
-
|
|
323
263
|
class __create_deployed_spec(typing_extensions.Protocol):
|
|
324
264
|
def __call__(
|
|
325
265
|
self,
|