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/image.pyi
CHANGED
|
@@ -2,6 +2,7 @@ import collections.abc
|
|
|
2
2
|
import google.protobuf.message
|
|
3
3
|
import modal._functions
|
|
4
4
|
import modal._object
|
|
5
|
+
import modal.app
|
|
5
6
|
import modal.client
|
|
6
7
|
import modal.cloud_bucket_mount
|
|
7
8
|
import modal.functions
|
|
@@ -90,8 +91,7 @@ def _create_context_mount_function(
|
|
|
90
91
|
],
|
|
91
92
|
dockerfile_cmds: list[str] = [],
|
|
92
93
|
dockerfile_path: typing.Optional[pathlib.Path] = None,
|
|
93
|
-
|
|
94
|
-
context_dir: typing.Union[pathlib.Path, str, None] = None,
|
|
94
|
+
context_dir: typing.Union[str, pathlib.Path, None] = None,
|
|
95
95
|
): ...
|
|
96
96
|
|
|
97
97
|
class _ImageRegistryConfig:
|
|
@@ -166,7 +166,7 @@ class _Image(modal._object._Object):
|
|
|
166
166
|
[typing.Literal["2023.12", "2024.04", "2024.10", "2025.06", "PREVIEW"]], DockerfileSpec
|
|
167
167
|
]
|
|
168
168
|
] = None,
|
|
169
|
-
secrets: typing.Optional[collections.abc.
|
|
169
|
+
secrets: typing.Optional[collections.abc.Collection[modal.secret._Secret]] = None,
|
|
170
170
|
gpu_config: typing.Optional[modal_proto.api_pb2.GPUConfig] = None,
|
|
171
171
|
build_function: typing.Optional[modal._functions._Function] = None,
|
|
172
172
|
build_function_input: typing.Optional[modal_proto.api_pb2.FunctionInput] = None,
|
|
@@ -176,6 +176,7 @@ class _Image(modal._object._Object):
|
|
|
176
176
|
] = None,
|
|
177
177
|
force_build: bool = False,
|
|
178
178
|
build_args: dict[str, str] = {},
|
|
179
|
+
validated_volumes: typing.Optional[collections.abc.Sequence[tuple[str, modal.volume._Volume]]] = None,
|
|
179
180
|
_namespace: int = 1,
|
|
180
181
|
_do_assert_no_mount_layers: bool = True,
|
|
181
182
|
): ...
|
|
@@ -318,6 +319,59 @@ class _Image(modal._object._Object):
|
|
|
318
319
|
"""
|
|
319
320
|
...
|
|
320
321
|
|
|
322
|
+
async def build(self, app: modal.app._App) -> _Image:
|
|
323
|
+
"""Eagerly build an image.
|
|
324
|
+
|
|
325
|
+
If your image was previously built, then this method will not rebuild your image
|
|
326
|
+
and your cached image is returned.
|
|
327
|
+
|
|
328
|
+
**Examples**
|
|
329
|
+
|
|
330
|
+
```python
|
|
331
|
+
image = modal.Image.debian_slim().uv_pip_install("scipy", "numpy")
|
|
332
|
+
|
|
333
|
+
app = modal.App.lookup("build-image", create_if_missing=True)
|
|
334
|
+
with modal.enable_output(): # To see logs in your local terminal
|
|
335
|
+
image.build(app)
|
|
336
|
+
|
|
337
|
+
# Save the image id
|
|
338
|
+
my_image_id = image.object_id
|
|
339
|
+
|
|
340
|
+
# Reference the image with the id or uses it another context.
|
|
341
|
+
built_image = modal.Image.from_id(my_image_id)
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
Alternatively, you can pre-build a image and use it in a sandbox.
|
|
345
|
+
|
|
346
|
+
```python notest
|
|
347
|
+
app = modal.App.lookup("sandbox-example", create_if_missing=True)
|
|
348
|
+
|
|
349
|
+
with modal.enable_output():
|
|
350
|
+
image = modal.Image.debian_slim().uv_pip_install("scipy")
|
|
351
|
+
image.build(app)
|
|
352
|
+
|
|
353
|
+
sb = modal.Sandbox.create("python", "-c", "import scipy; print(scipy)", app=app, image=image)
|
|
354
|
+
print(sb.stdout.read())
|
|
355
|
+
sb.terminate()
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
**Note**
|
|
359
|
+
|
|
360
|
+
For defining Modal functions, images are built automatically when deploying or running an App.
|
|
361
|
+
You do not need to built the image explicitly:
|
|
362
|
+
|
|
363
|
+
```python notest
|
|
364
|
+
app = modal.App()
|
|
365
|
+
image = modal.Image.debian_slim()
|
|
366
|
+
|
|
367
|
+
# No need to explicitly build the image for defining a function.
|
|
368
|
+
@app.function(image=image)
|
|
369
|
+
def f():
|
|
370
|
+
...
|
|
371
|
+
```
|
|
372
|
+
"""
|
|
373
|
+
...
|
|
374
|
+
|
|
321
375
|
def pip_install(
|
|
322
376
|
self,
|
|
323
377
|
*packages: typing.Union[str, list[str]],
|
|
@@ -327,7 +381,8 @@ class _Image(modal._object._Object):
|
|
|
327
381
|
pre: bool = False,
|
|
328
382
|
extra_options: str = "",
|
|
329
383
|
force_build: bool = False,
|
|
330
|
-
|
|
384
|
+
env: typing.Optional[dict[str, typing.Optional[str]]] = None,
|
|
385
|
+
secrets: typing.Optional[collections.abc.Collection[modal.secret._Secret]] = None,
|
|
331
386
|
gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
|
|
332
387
|
) -> _Image:
|
|
333
388
|
"""Install a list of Python packages using pip.
|
|
@@ -369,7 +424,8 @@ class _Image(modal._object._Object):
|
|
|
369
424
|
pre: bool = False,
|
|
370
425
|
extra_options: str = "",
|
|
371
426
|
gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
|
|
372
|
-
|
|
427
|
+
env: typing.Optional[dict[str, typing.Optional[str]]] = None,
|
|
428
|
+
secrets: typing.Optional[collections.abc.Collection[modal.secret._Secret]] = None,
|
|
373
429
|
force_build: bool = False,
|
|
374
430
|
) -> _Image:
|
|
375
431
|
"""Install a list of Python packages from private git repositories using pip.
|
|
@@ -414,7 +470,8 @@ class _Image(modal._object._Object):
|
|
|
414
470
|
pre: bool = False,
|
|
415
471
|
extra_options: str = "",
|
|
416
472
|
force_build: bool = False,
|
|
417
|
-
|
|
473
|
+
env: typing.Optional[dict[str, typing.Optional[str]]] = None,
|
|
474
|
+
secrets: typing.Optional[collections.abc.Collection[modal.secret._Secret]] = None,
|
|
418
475
|
gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
|
|
419
476
|
) -> _Image:
|
|
420
477
|
"""Install a list of Python packages from a local `requirements.txt` file."""
|
|
@@ -431,7 +488,8 @@ class _Image(modal._object._Object):
|
|
|
431
488
|
pre: bool = False,
|
|
432
489
|
extra_options: str = "",
|
|
433
490
|
force_build: bool = False,
|
|
434
|
-
|
|
491
|
+
env: typing.Optional[dict[str, typing.Optional[str]]] = None,
|
|
492
|
+
secrets: typing.Optional[collections.abc.Collection[modal.secret._Secret]] = None,
|
|
435
493
|
gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
|
|
436
494
|
) -> _Image:
|
|
437
495
|
"""Install dependencies specified by a local `pyproject.toml` file.
|
|
@@ -454,7 +512,8 @@ class _Image(modal._object._Object):
|
|
|
454
512
|
extra_options: str = "",
|
|
455
513
|
force_build: bool = False,
|
|
456
514
|
uv_version: typing.Optional[str] = None,
|
|
457
|
-
|
|
515
|
+
env: typing.Optional[dict[str, typing.Optional[str]]] = None,
|
|
516
|
+
secrets: typing.Optional[collections.abc.Collection[modal.secret._Secret]] = None,
|
|
458
517
|
gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
|
|
459
518
|
) -> _Image:
|
|
460
519
|
"""Install a list of Python packages using uv pip install.
|
|
@@ -470,6 +529,8 @@ class _Image(modal._object._Object):
|
|
|
470
529
|
- Python is on the `$PATH` and dependencies are installed with the first Python on the `$PATH`.
|
|
471
530
|
- Shell supports backticks for substitution
|
|
472
531
|
- `which` command is on the `$PATH`
|
|
532
|
+
|
|
533
|
+
Added in v1.1.0.
|
|
473
534
|
"""
|
|
474
535
|
...
|
|
475
536
|
|
|
@@ -485,7 +546,8 @@ class _Image(modal._object._Object):
|
|
|
485
546
|
only: list[str] = [],
|
|
486
547
|
poetry_version: typing.Optional[str] = "latest",
|
|
487
548
|
old_installer: bool = False,
|
|
488
|
-
|
|
549
|
+
env: typing.Optional[dict[str, typing.Optional[str]]] = None,
|
|
550
|
+
secrets: typing.Optional[collections.abc.Collection[modal.secret._Secret]] = None,
|
|
489
551
|
gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
|
|
490
552
|
) -> _Image:
|
|
491
553
|
"""Install poetry *dependencies* specified by a local `pyproject.toml` file.
|
|
@@ -512,7 +574,8 @@ class _Image(modal._object._Object):
|
|
|
512
574
|
frozen: bool = True,
|
|
513
575
|
extra_options: str = "",
|
|
514
576
|
uv_version: typing.Optional[str] = None,
|
|
515
|
-
|
|
577
|
+
env: typing.Optional[dict[str, typing.Optional[str]]] = None,
|
|
578
|
+
secrets: typing.Optional[collections.abc.Collection[modal.secret._Secret]] = None,
|
|
516
579
|
gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
|
|
517
580
|
) -> _Image:
|
|
518
581
|
"""Creates a virtual environment with the dependencies in a uv managed project with `uv sync`.
|
|
@@ -521,6 +584,20 @@ class _Image(modal._object._Object):
|
|
|
521
584
|
```python
|
|
522
585
|
image = modal.Image.debian_slim().uv_sync()
|
|
523
586
|
```
|
|
587
|
+
|
|
588
|
+
The `pyproject.toml` and `uv.lock` in `uv_project_dir` are automatically added to the build context. The
|
|
589
|
+
`uv_project_dir` is relative to the current working directory of where `modal` is called.
|
|
590
|
+
|
|
591
|
+
NOTE: This does *not* install the project itself into the environment (this is equivalent to the
|
|
592
|
+
`--no-install-project` flag in the `uv sync` command) and you would be expected to add any local python source
|
|
593
|
+
files using `Image.add_local_python_source` or similar methods after this call.
|
|
594
|
+
|
|
595
|
+
This ensures that updates to your project code wouldn't require reinstalling third-party dependencies
|
|
596
|
+
after every change.
|
|
597
|
+
|
|
598
|
+
uv workspaces are currently not supported.
|
|
599
|
+
|
|
600
|
+
Added in v1.1.0.
|
|
524
601
|
"""
|
|
525
602
|
...
|
|
526
603
|
|
|
@@ -528,10 +605,10 @@ class _Image(modal._object._Object):
|
|
|
528
605
|
self,
|
|
529
606
|
*dockerfile_commands: typing.Union[str, list[str]],
|
|
530
607
|
context_files: dict[str, str] = {},
|
|
531
|
-
|
|
608
|
+
env: typing.Optional[dict[str, typing.Optional[str]]] = None,
|
|
609
|
+
secrets: typing.Optional[collections.abc.Collection[modal.secret._Secret]] = None,
|
|
532
610
|
gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
|
|
533
|
-
|
|
534
|
-
context_dir: typing.Union[pathlib.Path, str, None] = None,
|
|
611
|
+
context_dir: typing.Union[str, pathlib.Path, None] = None,
|
|
535
612
|
force_build: bool = False,
|
|
536
613
|
ignore: typing.Union[
|
|
537
614
|
collections.abc.Sequence[str], collections.abc.Callable[[pathlib.Path], bool]
|
|
@@ -580,7 +657,7 @@ class _Image(modal._object._Object):
|
|
|
580
657
|
...
|
|
581
658
|
|
|
582
659
|
def entrypoint(self, entrypoint_commands: list[str]) -> _Image:
|
|
583
|
-
"""Set the
|
|
660
|
+
"""Set the ENTRYPOINT for the image."""
|
|
584
661
|
...
|
|
585
662
|
|
|
586
663
|
def shell(self, shell_commands: list[str]) -> _Image:
|
|
@@ -590,7 +667,9 @@ class _Image(modal._object._Object):
|
|
|
590
667
|
def run_commands(
|
|
591
668
|
self,
|
|
592
669
|
*commands: typing.Union[str, list[str]],
|
|
593
|
-
|
|
670
|
+
env: typing.Optional[dict[str, typing.Optional[str]]] = None,
|
|
671
|
+
secrets: typing.Optional[collections.abc.Collection[modal.secret._Secret]] = None,
|
|
672
|
+
volumes: typing.Optional[dict[typing.Union[str, pathlib.PurePosixPath], modal.volume._Volume]] = None,
|
|
594
673
|
gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
|
|
595
674
|
force_build: bool = False,
|
|
596
675
|
) -> _Image:
|
|
@@ -608,7 +687,8 @@ class _Image(modal._object._Object):
|
|
|
608
687
|
spec_file: typing.Optional[str] = None,
|
|
609
688
|
channels: list[str] = [],
|
|
610
689
|
force_build: bool = False,
|
|
611
|
-
|
|
690
|
+
env: typing.Optional[dict[str, typing.Optional[str]]] = None,
|
|
691
|
+
secrets: typing.Optional[collections.abc.Collection[modal.secret._Secret]] = None,
|
|
612
692
|
gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
|
|
613
693
|
) -> _Image:
|
|
614
694
|
"""Install a list of additional packages using micromamba."""
|
|
@@ -713,12 +793,18 @@ class _Image(modal._object._Object):
|
|
|
713
793
|
) -> _Image:
|
|
714
794
|
"""Build a Modal image from a private image in AWS Elastic Container Registry (ECR).
|
|
715
795
|
|
|
716
|
-
You will need to pass a `modal.Secret` containing
|
|
717
|
-
|
|
796
|
+
You will need to pass a `modal.Secret` containing either IAM user credentials or OIDC
|
|
797
|
+
configuration to access the target ECR registry.
|
|
798
|
+
|
|
799
|
+
For IAM user authentication, set `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and `AWS_REGION`.
|
|
800
|
+
|
|
801
|
+
For OIDC authentication, set `AWS_ROLE_ARN` and `AWS_REGION`.
|
|
718
802
|
|
|
719
803
|
IAM configuration details can be found in the AWS documentation for
|
|
720
804
|
["Private repository policies"](https://docs.aws.amazon.com/AmazonECR/latest/userguide/repository-policies.html).
|
|
721
805
|
|
|
806
|
+
For more details on using an AWS role to access ECR, see the [OIDC integration guide](https://modal.com/docs/guide/oidc-integration).
|
|
807
|
+
|
|
722
808
|
See `Image.from_registry()` for information about the other parameters.
|
|
723
809
|
|
|
724
810
|
**Example**
|
|
@@ -740,10 +826,10 @@ class _Image(modal._object._Object):
|
|
|
740
826
|
def from_dockerfile(
|
|
741
827
|
path: typing.Union[str, pathlib.Path],
|
|
742
828
|
*,
|
|
743
|
-
context_mount: typing.Optional[modal.mount._Mount] = None,
|
|
744
829
|
force_build: bool = False,
|
|
745
|
-
context_dir: typing.Union[pathlib.Path,
|
|
746
|
-
|
|
830
|
+
context_dir: typing.Union[str, pathlib.Path, None] = None,
|
|
831
|
+
env: typing.Optional[dict[str, typing.Optional[str]]] = None,
|
|
832
|
+
secrets: typing.Optional[collections.abc.Collection[modal.secret._Secret]] = None,
|
|
747
833
|
gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
|
|
748
834
|
add_python: typing.Optional[str] = None,
|
|
749
835
|
build_args: dict[str, str] = {},
|
|
@@ -811,7 +897,8 @@ class _Image(modal._object._Object):
|
|
|
811
897
|
self,
|
|
812
898
|
*packages: typing.Union[str, list[str]],
|
|
813
899
|
force_build: bool = False,
|
|
814
|
-
|
|
900
|
+
env: typing.Optional[dict[str, typing.Optional[str]]] = None,
|
|
901
|
+
secrets: typing.Optional[collections.abc.Collection[modal.secret._Secret]] = None,
|
|
815
902
|
gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
|
|
816
903
|
) -> _Image:
|
|
817
904
|
"""Install a list of Debian packages using `apt`.
|
|
@@ -828,8 +915,8 @@ class _Image(modal._object._Object):
|
|
|
828
915
|
self,
|
|
829
916
|
raw_f: collections.abc.Callable[..., typing.Any],
|
|
830
917
|
*,
|
|
831
|
-
|
|
832
|
-
|
|
918
|
+
env: typing.Optional[dict[str, typing.Optional[str]]] = None,
|
|
919
|
+
secrets: typing.Optional[collections.abc.Collection[modal.secret._Secret]] = None,
|
|
833
920
|
volumes: dict[
|
|
834
921
|
typing.Union[str, pathlib.PurePosixPath],
|
|
835
922
|
typing.Union[modal.volume._Volume, modal.cloud_bucket_mount._CloudBucketMount],
|
|
@@ -837,20 +924,22 @@ class _Image(modal._object._Object):
|
|
|
837
924
|
network_file_systems: dict[
|
|
838
925
|
typing.Union[str, pathlib.PurePosixPath], modal.network_file_system._NetworkFileSystem
|
|
839
926
|
] = {},
|
|
927
|
+
gpu: typing.Union[None, str, modal.gpu._GPUConfig, list[typing.Union[None, str, modal.gpu._GPUConfig]]] = None,
|
|
840
928
|
cpu: typing.Optional[float] = None,
|
|
841
929
|
memory: typing.Optional[int] = None,
|
|
842
|
-
timeout:
|
|
843
|
-
force_build: bool = False,
|
|
930
|
+
timeout: int = 3600,
|
|
844
931
|
cloud: typing.Optional[str] = None,
|
|
845
932
|
region: typing.Union[str, collections.abc.Sequence[str], None] = None,
|
|
933
|
+
force_build: bool = False,
|
|
846
934
|
args: collections.abc.Sequence[typing.Any] = (),
|
|
847
935
|
kwargs: dict[str, typing.Any] = {},
|
|
848
|
-
include_source:
|
|
936
|
+
include_source: bool = True,
|
|
849
937
|
) -> _Image:
|
|
850
|
-
"""Run user-defined function `raw_f` as an image build step.
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
938
|
+
"""Run user-defined function `raw_f` as an image build step.
|
|
939
|
+
|
|
940
|
+
The function runs like an ordinary Modal Function, accepting a resource configuration and integrating
|
|
941
|
+
with Modal features like Secrets and Volumes. Unlike ordinary Modal Functions, any changes to the
|
|
942
|
+
filesystem state will be captured on container exit and saved as a new Image.
|
|
854
943
|
|
|
855
944
|
**Note**
|
|
856
945
|
|
|
@@ -907,7 +996,9 @@ class _Image(modal._object._Object):
|
|
|
907
996
|
...
|
|
908
997
|
|
|
909
998
|
def cmd(self, cmd: list[str]) -> _Image:
|
|
910
|
-
"""Set the default
|
|
999
|
+
"""Set the default command (`CMD`) to run when a container is started.
|
|
1000
|
+
|
|
1001
|
+
Used with `modal.Sandbox`. Has no effect on `modal.Function`.
|
|
911
1002
|
|
|
912
1003
|
**Example**
|
|
913
1004
|
|
|
@@ -992,7 +1083,7 @@ class Image(modal.object.Object):
|
|
|
992
1083
|
[typing.Literal["2023.12", "2024.04", "2024.10", "2025.06", "PREVIEW"]], DockerfileSpec
|
|
993
1084
|
]
|
|
994
1085
|
] = None,
|
|
995
|
-
secrets: typing.Optional[collections.abc.
|
|
1086
|
+
secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
|
|
996
1087
|
gpu_config: typing.Optional[modal_proto.api_pb2.GPUConfig] = None,
|
|
997
1088
|
build_function: typing.Optional[modal.functions.Function] = None,
|
|
998
1089
|
build_function_input: typing.Optional[modal_proto.api_pb2.FunctionInput] = None,
|
|
@@ -1002,6 +1093,7 @@ class Image(modal.object.Object):
|
|
|
1002
1093
|
] = None,
|
|
1003
1094
|
force_build: bool = False,
|
|
1004
1095
|
build_args: dict[str, str] = {},
|
|
1096
|
+
validated_volumes: typing.Optional[collections.abc.Sequence[tuple[str, modal.volume.Volume]]] = None,
|
|
1005
1097
|
_namespace: int = 1,
|
|
1006
1098
|
_do_assert_no_mount_layers: bool = True,
|
|
1007
1099
|
): ...
|
|
@@ -1153,6 +1245,115 @@ class Image(modal.object.Object):
|
|
|
1153
1245
|
|
|
1154
1246
|
from_id: __from_id_spec
|
|
1155
1247
|
|
|
1248
|
+
class __build_spec(typing_extensions.Protocol[SUPERSELF]):
|
|
1249
|
+
def __call__(self, /, app: modal.app.App) -> Image:
|
|
1250
|
+
"""Eagerly build an image.
|
|
1251
|
+
|
|
1252
|
+
If your image was previously built, then this method will not rebuild your image
|
|
1253
|
+
and your cached image is returned.
|
|
1254
|
+
|
|
1255
|
+
**Examples**
|
|
1256
|
+
|
|
1257
|
+
```python
|
|
1258
|
+
image = modal.Image.debian_slim().uv_pip_install("scipy", "numpy")
|
|
1259
|
+
|
|
1260
|
+
app = modal.App.lookup("build-image", create_if_missing=True)
|
|
1261
|
+
with modal.enable_output(): # To see logs in your local terminal
|
|
1262
|
+
image.build(app)
|
|
1263
|
+
|
|
1264
|
+
# Save the image id
|
|
1265
|
+
my_image_id = image.object_id
|
|
1266
|
+
|
|
1267
|
+
# Reference the image with the id or uses it another context.
|
|
1268
|
+
built_image = modal.Image.from_id(my_image_id)
|
|
1269
|
+
```
|
|
1270
|
+
|
|
1271
|
+
Alternatively, you can pre-build a image and use it in a sandbox.
|
|
1272
|
+
|
|
1273
|
+
```python notest
|
|
1274
|
+
app = modal.App.lookup("sandbox-example", create_if_missing=True)
|
|
1275
|
+
|
|
1276
|
+
with modal.enable_output():
|
|
1277
|
+
image = modal.Image.debian_slim().uv_pip_install("scipy")
|
|
1278
|
+
image.build(app)
|
|
1279
|
+
|
|
1280
|
+
sb = modal.Sandbox.create("python", "-c", "import scipy; print(scipy)", app=app, image=image)
|
|
1281
|
+
print(sb.stdout.read())
|
|
1282
|
+
sb.terminate()
|
|
1283
|
+
```
|
|
1284
|
+
|
|
1285
|
+
**Note**
|
|
1286
|
+
|
|
1287
|
+
For defining Modal functions, images are built automatically when deploying or running an App.
|
|
1288
|
+
You do not need to built the image explicitly:
|
|
1289
|
+
|
|
1290
|
+
```python notest
|
|
1291
|
+
app = modal.App()
|
|
1292
|
+
image = modal.Image.debian_slim()
|
|
1293
|
+
|
|
1294
|
+
# No need to explicitly build the image for defining a function.
|
|
1295
|
+
@app.function(image=image)
|
|
1296
|
+
def f():
|
|
1297
|
+
...
|
|
1298
|
+
```
|
|
1299
|
+
"""
|
|
1300
|
+
...
|
|
1301
|
+
|
|
1302
|
+
async def aio(self, /, app: modal.app.App) -> Image:
|
|
1303
|
+
"""Eagerly build an image.
|
|
1304
|
+
|
|
1305
|
+
If your image was previously built, then this method will not rebuild your image
|
|
1306
|
+
and your cached image is returned.
|
|
1307
|
+
|
|
1308
|
+
**Examples**
|
|
1309
|
+
|
|
1310
|
+
```python
|
|
1311
|
+
image = modal.Image.debian_slim().uv_pip_install("scipy", "numpy")
|
|
1312
|
+
|
|
1313
|
+
app = modal.App.lookup("build-image", create_if_missing=True)
|
|
1314
|
+
with modal.enable_output(): # To see logs in your local terminal
|
|
1315
|
+
image.build(app)
|
|
1316
|
+
|
|
1317
|
+
# Save the image id
|
|
1318
|
+
my_image_id = image.object_id
|
|
1319
|
+
|
|
1320
|
+
# Reference the image with the id or uses it another context.
|
|
1321
|
+
built_image = modal.Image.from_id(my_image_id)
|
|
1322
|
+
```
|
|
1323
|
+
|
|
1324
|
+
Alternatively, you can pre-build a image and use it in a sandbox.
|
|
1325
|
+
|
|
1326
|
+
```python notest
|
|
1327
|
+
app = modal.App.lookup("sandbox-example", create_if_missing=True)
|
|
1328
|
+
|
|
1329
|
+
with modal.enable_output():
|
|
1330
|
+
image = modal.Image.debian_slim().uv_pip_install("scipy")
|
|
1331
|
+
image.build(app)
|
|
1332
|
+
|
|
1333
|
+
sb = modal.Sandbox.create("python", "-c", "import scipy; print(scipy)", app=app, image=image)
|
|
1334
|
+
print(sb.stdout.read())
|
|
1335
|
+
sb.terminate()
|
|
1336
|
+
```
|
|
1337
|
+
|
|
1338
|
+
**Note**
|
|
1339
|
+
|
|
1340
|
+
For defining Modal functions, images are built automatically when deploying or running an App.
|
|
1341
|
+
You do not need to built the image explicitly:
|
|
1342
|
+
|
|
1343
|
+
```python notest
|
|
1344
|
+
app = modal.App()
|
|
1345
|
+
image = modal.Image.debian_slim()
|
|
1346
|
+
|
|
1347
|
+
# No need to explicitly build the image for defining a function.
|
|
1348
|
+
@app.function(image=image)
|
|
1349
|
+
def f():
|
|
1350
|
+
...
|
|
1351
|
+
```
|
|
1352
|
+
"""
|
|
1353
|
+
...
|
|
1354
|
+
|
|
1355
|
+
build: __build_spec[typing_extensions.Self]
|
|
1356
|
+
|
|
1156
1357
|
def pip_install(
|
|
1157
1358
|
self,
|
|
1158
1359
|
*packages: typing.Union[str, list[str]],
|
|
@@ -1162,7 +1363,8 @@ class Image(modal.object.Object):
|
|
|
1162
1363
|
pre: bool = False,
|
|
1163
1364
|
extra_options: str = "",
|
|
1164
1365
|
force_build: bool = False,
|
|
1165
|
-
|
|
1366
|
+
env: typing.Optional[dict[str, typing.Optional[str]]] = None,
|
|
1367
|
+
secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
|
|
1166
1368
|
gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
|
|
1167
1369
|
) -> Image:
|
|
1168
1370
|
"""Install a list of Python packages using pip.
|
|
@@ -1204,7 +1406,8 @@ class Image(modal.object.Object):
|
|
|
1204
1406
|
pre: bool = False,
|
|
1205
1407
|
extra_options: str = "",
|
|
1206
1408
|
gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
|
|
1207
|
-
|
|
1409
|
+
env: typing.Optional[dict[str, typing.Optional[str]]] = None,
|
|
1410
|
+
secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
|
|
1208
1411
|
force_build: bool = False,
|
|
1209
1412
|
) -> Image:
|
|
1210
1413
|
"""Install a list of Python packages from private git repositories using pip.
|
|
@@ -1249,7 +1452,8 @@ class Image(modal.object.Object):
|
|
|
1249
1452
|
pre: bool = False,
|
|
1250
1453
|
extra_options: str = "",
|
|
1251
1454
|
force_build: bool = False,
|
|
1252
|
-
|
|
1455
|
+
env: typing.Optional[dict[str, typing.Optional[str]]] = None,
|
|
1456
|
+
secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
|
|
1253
1457
|
gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
|
|
1254
1458
|
) -> Image:
|
|
1255
1459
|
"""Install a list of Python packages from a local `requirements.txt` file."""
|
|
@@ -1266,7 +1470,8 @@ class Image(modal.object.Object):
|
|
|
1266
1470
|
pre: bool = False,
|
|
1267
1471
|
extra_options: str = "",
|
|
1268
1472
|
force_build: bool = False,
|
|
1269
|
-
|
|
1473
|
+
env: typing.Optional[dict[str, typing.Optional[str]]] = None,
|
|
1474
|
+
secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
|
|
1270
1475
|
gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
|
|
1271
1476
|
) -> Image:
|
|
1272
1477
|
"""Install dependencies specified by a local `pyproject.toml` file.
|
|
@@ -1289,7 +1494,8 @@ class Image(modal.object.Object):
|
|
|
1289
1494
|
extra_options: str = "",
|
|
1290
1495
|
force_build: bool = False,
|
|
1291
1496
|
uv_version: typing.Optional[str] = None,
|
|
1292
|
-
|
|
1497
|
+
env: typing.Optional[dict[str, typing.Optional[str]]] = None,
|
|
1498
|
+
secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
|
|
1293
1499
|
gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
|
|
1294
1500
|
) -> Image:
|
|
1295
1501
|
"""Install a list of Python packages using uv pip install.
|
|
@@ -1305,6 +1511,8 @@ class Image(modal.object.Object):
|
|
|
1305
1511
|
- Python is on the `$PATH` and dependencies are installed with the first Python on the `$PATH`.
|
|
1306
1512
|
- Shell supports backticks for substitution
|
|
1307
1513
|
- `which` command is on the `$PATH`
|
|
1514
|
+
|
|
1515
|
+
Added in v1.1.0.
|
|
1308
1516
|
"""
|
|
1309
1517
|
...
|
|
1310
1518
|
|
|
@@ -1320,7 +1528,8 @@ class Image(modal.object.Object):
|
|
|
1320
1528
|
only: list[str] = [],
|
|
1321
1529
|
poetry_version: typing.Optional[str] = "latest",
|
|
1322
1530
|
old_installer: bool = False,
|
|
1323
|
-
|
|
1531
|
+
env: typing.Optional[dict[str, typing.Optional[str]]] = None,
|
|
1532
|
+
secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
|
|
1324
1533
|
gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
|
|
1325
1534
|
) -> Image:
|
|
1326
1535
|
"""Install poetry *dependencies* specified by a local `pyproject.toml` file.
|
|
@@ -1347,7 +1556,8 @@ class Image(modal.object.Object):
|
|
|
1347
1556
|
frozen: bool = True,
|
|
1348
1557
|
extra_options: str = "",
|
|
1349
1558
|
uv_version: typing.Optional[str] = None,
|
|
1350
|
-
|
|
1559
|
+
env: typing.Optional[dict[str, typing.Optional[str]]] = None,
|
|
1560
|
+
secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
|
|
1351
1561
|
gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
|
|
1352
1562
|
) -> Image:
|
|
1353
1563
|
"""Creates a virtual environment with the dependencies in a uv managed project with `uv sync`.
|
|
@@ -1356,6 +1566,20 @@ class Image(modal.object.Object):
|
|
|
1356
1566
|
```python
|
|
1357
1567
|
image = modal.Image.debian_slim().uv_sync()
|
|
1358
1568
|
```
|
|
1569
|
+
|
|
1570
|
+
The `pyproject.toml` and `uv.lock` in `uv_project_dir` are automatically added to the build context. The
|
|
1571
|
+
`uv_project_dir` is relative to the current working directory of where `modal` is called.
|
|
1572
|
+
|
|
1573
|
+
NOTE: This does *not* install the project itself into the environment (this is equivalent to the
|
|
1574
|
+
`--no-install-project` flag in the `uv sync` command) and you would be expected to add any local python source
|
|
1575
|
+
files using `Image.add_local_python_source` or similar methods after this call.
|
|
1576
|
+
|
|
1577
|
+
This ensures that updates to your project code wouldn't require reinstalling third-party dependencies
|
|
1578
|
+
after every change.
|
|
1579
|
+
|
|
1580
|
+
uv workspaces are currently not supported.
|
|
1581
|
+
|
|
1582
|
+
Added in v1.1.0.
|
|
1359
1583
|
"""
|
|
1360
1584
|
...
|
|
1361
1585
|
|
|
@@ -1363,10 +1587,10 @@ class Image(modal.object.Object):
|
|
|
1363
1587
|
self,
|
|
1364
1588
|
*dockerfile_commands: typing.Union[str, list[str]],
|
|
1365
1589
|
context_files: dict[str, str] = {},
|
|
1366
|
-
|
|
1590
|
+
env: typing.Optional[dict[str, typing.Optional[str]]] = None,
|
|
1591
|
+
secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
|
|
1367
1592
|
gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
|
|
1368
|
-
|
|
1369
|
-
context_dir: typing.Union[pathlib.Path, str, None] = None,
|
|
1593
|
+
context_dir: typing.Union[str, pathlib.Path, None] = None,
|
|
1370
1594
|
force_build: bool = False,
|
|
1371
1595
|
ignore: typing.Union[
|
|
1372
1596
|
collections.abc.Sequence[str], collections.abc.Callable[[pathlib.Path], bool]
|
|
@@ -1415,7 +1639,7 @@ class Image(modal.object.Object):
|
|
|
1415
1639
|
...
|
|
1416
1640
|
|
|
1417
1641
|
def entrypoint(self, entrypoint_commands: list[str]) -> Image:
|
|
1418
|
-
"""Set the
|
|
1642
|
+
"""Set the ENTRYPOINT for the image."""
|
|
1419
1643
|
...
|
|
1420
1644
|
|
|
1421
1645
|
def shell(self, shell_commands: list[str]) -> Image:
|
|
@@ -1425,7 +1649,9 @@ class Image(modal.object.Object):
|
|
|
1425
1649
|
def run_commands(
|
|
1426
1650
|
self,
|
|
1427
1651
|
*commands: typing.Union[str, list[str]],
|
|
1428
|
-
|
|
1652
|
+
env: typing.Optional[dict[str, typing.Optional[str]]] = None,
|
|
1653
|
+
secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
|
|
1654
|
+
volumes: typing.Optional[dict[typing.Union[str, pathlib.PurePosixPath], modal.volume.Volume]] = None,
|
|
1429
1655
|
gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
|
|
1430
1656
|
force_build: bool = False,
|
|
1431
1657
|
) -> Image:
|
|
@@ -1443,7 +1669,8 @@ class Image(modal.object.Object):
|
|
|
1443
1669
|
spec_file: typing.Optional[str] = None,
|
|
1444
1670
|
channels: list[str] = [],
|
|
1445
1671
|
force_build: bool = False,
|
|
1446
|
-
|
|
1672
|
+
env: typing.Optional[dict[str, typing.Optional[str]]] = None,
|
|
1673
|
+
secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
|
|
1447
1674
|
gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
|
|
1448
1675
|
) -> Image:
|
|
1449
1676
|
"""Install a list of additional packages using micromamba."""
|
|
@@ -1548,12 +1775,18 @@ class Image(modal.object.Object):
|
|
|
1548
1775
|
) -> Image:
|
|
1549
1776
|
"""Build a Modal image from a private image in AWS Elastic Container Registry (ECR).
|
|
1550
1777
|
|
|
1551
|
-
You will need to pass a `modal.Secret` containing
|
|
1552
|
-
|
|
1778
|
+
You will need to pass a `modal.Secret` containing either IAM user credentials or OIDC
|
|
1779
|
+
configuration to access the target ECR registry.
|
|
1780
|
+
|
|
1781
|
+
For IAM user authentication, set `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and `AWS_REGION`.
|
|
1782
|
+
|
|
1783
|
+
For OIDC authentication, set `AWS_ROLE_ARN` and `AWS_REGION`.
|
|
1553
1784
|
|
|
1554
1785
|
IAM configuration details can be found in the AWS documentation for
|
|
1555
1786
|
["Private repository policies"](https://docs.aws.amazon.com/AmazonECR/latest/userguide/repository-policies.html).
|
|
1556
1787
|
|
|
1788
|
+
For more details on using an AWS role to access ECR, see the [OIDC integration guide](https://modal.com/docs/guide/oidc-integration).
|
|
1789
|
+
|
|
1557
1790
|
See `Image.from_registry()` for information about the other parameters.
|
|
1558
1791
|
|
|
1559
1792
|
**Example**
|
|
@@ -1575,10 +1808,10 @@ class Image(modal.object.Object):
|
|
|
1575
1808
|
def from_dockerfile(
|
|
1576
1809
|
path: typing.Union[str, pathlib.Path],
|
|
1577
1810
|
*,
|
|
1578
|
-
context_mount: typing.Optional[modal.mount.Mount] = None,
|
|
1579
1811
|
force_build: bool = False,
|
|
1580
|
-
context_dir: typing.Union[pathlib.Path,
|
|
1581
|
-
|
|
1812
|
+
context_dir: typing.Union[str, pathlib.Path, None] = None,
|
|
1813
|
+
env: typing.Optional[dict[str, typing.Optional[str]]] = None,
|
|
1814
|
+
secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
|
|
1582
1815
|
gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
|
|
1583
1816
|
add_python: typing.Optional[str] = None,
|
|
1584
1817
|
build_args: dict[str, str] = {},
|
|
@@ -1646,7 +1879,8 @@ class Image(modal.object.Object):
|
|
|
1646
1879
|
self,
|
|
1647
1880
|
*packages: typing.Union[str, list[str]],
|
|
1648
1881
|
force_build: bool = False,
|
|
1649
|
-
|
|
1882
|
+
env: typing.Optional[dict[str, typing.Optional[str]]] = None,
|
|
1883
|
+
secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
|
|
1650
1884
|
gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
|
|
1651
1885
|
) -> Image:
|
|
1652
1886
|
"""Install a list of Debian packages using `apt`.
|
|
@@ -1663,8 +1897,8 @@ class Image(modal.object.Object):
|
|
|
1663
1897
|
self,
|
|
1664
1898
|
raw_f: collections.abc.Callable[..., typing.Any],
|
|
1665
1899
|
*,
|
|
1666
|
-
|
|
1667
|
-
|
|
1900
|
+
env: typing.Optional[dict[str, typing.Optional[str]]] = None,
|
|
1901
|
+
secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
|
|
1668
1902
|
volumes: dict[
|
|
1669
1903
|
typing.Union[str, pathlib.PurePosixPath],
|
|
1670
1904
|
typing.Union[modal.volume.Volume, modal.cloud_bucket_mount.CloudBucketMount],
|
|
@@ -1672,20 +1906,22 @@ class Image(modal.object.Object):
|
|
|
1672
1906
|
network_file_systems: dict[
|
|
1673
1907
|
typing.Union[str, pathlib.PurePosixPath], modal.network_file_system.NetworkFileSystem
|
|
1674
1908
|
] = {},
|
|
1909
|
+
gpu: typing.Union[None, str, modal.gpu._GPUConfig, list[typing.Union[None, str, modal.gpu._GPUConfig]]] = None,
|
|
1675
1910
|
cpu: typing.Optional[float] = None,
|
|
1676
1911
|
memory: typing.Optional[int] = None,
|
|
1677
|
-
timeout:
|
|
1678
|
-
force_build: bool = False,
|
|
1912
|
+
timeout: int = 3600,
|
|
1679
1913
|
cloud: typing.Optional[str] = None,
|
|
1680
1914
|
region: typing.Union[str, collections.abc.Sequence[str], None] = None,
|
|
1915
|
+
force_build: bool = False,
|
|
1681
1916
|
args: collections.abc.Sequence[typing.Any] = (),
|
|
1682
1917
|
kwargs: dict[str, typing.Any] = {},
|
|
1683
|
-
include_source:
|
|
1918
|
+
include_source: bool = True,
|
|
1684
1919
|
) -> Image:
|
|
1685
|
-
"""Run user-defined function `raw_f` as an image build step.
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1920
|
+
"""Run user-defined function `raw_f` as an image build step.
|
|
1921
|
+
|
|
1922
|
+
The function runs like an ordinary Modal Function, accepting a resource configuration and integrating
|
|
1923
|
+
with Modal features like Secrets and Volumes. Unlike ordinary Modal Functions, any changes to the
|
|
1924
|
+
filesystem state will be captured on container exit and saved as a new Image.
|
|
1689
1925
|
|
|
1690
1926
|
**Note**
|
|
1691
1927
|
|
|
@@ -1742,7 +1978,9 @@ class Image(modal.object.Object):
|
|
|
1742
1978
|
...
|
|
1743
1979
|
|
|
1744
1980
|
def cmd(self, cmd: list[str]) -> Image:
|
|
1745
|
-
"""Set the default
|
|
1981
|
+
"""Set the default command (`CMD`) to run when a container is started.
|
|
1982
|
+
|
|
1983
|
+
Used with `modal.Sandbox`. Has no effect on `modal.Function`.
|
|
1746
1984
|
|
|
1747
1985
|
**Example**
|
|
1748
1986
|
|