modal 0.72.4__py3-none-any.whl → 0.72.48__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.
- modal/_container_entrypoint.py +5 -10
- modal/_object.py +297 -0
- modal/_resolver.py +7 -5
- modal/_runtime/container_io_manager.py +0 -11
- modal/_runtime/user_code_imports.py +7 -7
- modal/_serialization.py +4 -3
- modal/_tunnel.py +1 -1
- modal/app.py +14 -61
- modal/app.pyi +25 -25
- modal/cli/app.py +3 -2
- modal/cli/container.py +1 -1
- modal/cli/import_refs.py +185 -113
- modal/cli/launch.py +10 -5
- modal/cli/programs/run_jupyter.py +2 -2
- modal/cli/programs/vscode.py +3 -3
- modal/cli/run.py +134 -68
- modal/client.py +1 -0
- modal/client.pyi +18 -14
- modal/cloud_bucket_mount.py +4 -0
- modal/cloud_bucket_mount.pyi +4 -0
- modal/cls.py +33 -5
- modal/cls.pyi +20 -5
- modal/container_process.pyi +8 -6
- modal/dict.py +1 -1
- modal/dict.pyi +32 -29
- modal/environments.py +1 -1
- modal/environments.pyi +2 -1
- modal/experimental.py +47 -11
- modal/experimental.pyi +29 -0
- modal/file_io.pyi +30 -28
- modal/file_pattern_matcher.py +32 -25
- modal/functions.py +31 -23
- modal/functions.pyi +57 -50
- modal/gpu.py +19 -26
- modal/image.py +47 -19
- modal/image.pyi +28 -21
- modal/io_streams.pyi +14 -12
- modal/mount.py +14 -5
- modal/mount.pyi +28 -25
- modal/network_file_system.py +7 -7
- modal/network_file_system.pyi +27 -24
- modal/object.py +2 -265
- modal/object.pyi +46 -130
- modal/parallel_map.py +2 -2
- modal/parallel_map.pyi +10 -7
- modal/partial_function.py +22 -3
- modal/partial_function.pyi +45 -27
- modal/proxy.py +1 -1
- modal/proxy.pyi +2 -1
- modal/queue.py +1 -1
- modal/queue.pyi +26 -23
- modal/runner.py +14 -3
- modal/sandbox.py +11 -7
- modal/sandbox.pyi +30 -27
- modal/secret.py +1 -1
- modal/secret.pyi +2 -1
- modal/token_flow.pyi +6 -4
- modal/volume.py +1 -1
- modal/volume.pyi +36 -33
- {modal-0.72.4.dist-info → modal-0.72.48.dist-info}/METADATA +2 -2
- {modal-0.72.4.dist-info → modal-0.72.48.dist-info}/RECORD +73 -71
- modal_proto/api.proto +151 -4
- modal_proto/api_grpc.py +113 -0
- modal_proto/api_pb2.py +998 -795
- modal_proto/api_pb2.pyi +430 -11
- modal_proto/api_pb2_grpc.py +233 -1
- modal_proto/api_pb2_grpc.pyi +75 -3
- modal_proto/modal_api_grpc.py +7 -0
- modal_version/_version_generated.py +1 -1
- {modal-0.72.4.dist-info → modal-0.72.48.dist-info}/LICENSE +0 -0
- {modal-0.72.4.dist-info → modal-0.72.48.dist-info}/WHEEL +0 -0
- {modal-0.72.4.dist-info → modal-0.72.48.dist-info}/entry_points.txt +0 -0
- {modal-0.72.4.dist-info → modal-0.72.48.dist-info}/top_level.txt +0 -0
modal/image.py
CHANGED
@@ -26,6 +26,7 @@ from grpclib.exceptions import GRPCError, StreamTerminatedError
|
|
26
26
|
|
27
27
|
from modal_proto import api_pb2
|
28
28
|
|
29
|
+
from ._object import _Object, live_method_gen
|
29
30
|
from ._resolver import Resolver
|
30
31
|
from ._serialization import serialize
|
31
32
|
from ._utils.async_utils import synchronize_api
|
@@ -46,7 +47,6 @@ from .file_pattern_matcher import NON_PYTHON_FILES, FilePatternMatcher, _ignore_
|
|
46
47
|
from .gpu import GPU_T, parse_gpu_config
|
47
48
|
from .mount import _Mount, python_standalone_mount_name
|
48
49
|
from .network_file_system import _NetworkFileSystem
|
49
|
-
from .object import _Object, live_method_gen
|
50
50
|
from .output import _get_output_manager
|
51
51
|
from .scheduler_placement import SchedulerPlacement
|
52
52
|
from .secret import _Secret
|
@@ -82,6 +82,11 @@ class _AutoDockerIgnoreSentinel:
|
|
82
82
|
|
83
83
|
AUTO_DOCKERIGNORE = _AutoDockerIgnoreSentinel()
|
84
84
|
|
85
|
+
COPY_DEPRECATION_MESSAGE_PATTERN = """modal.Image.copy_* methods will soon be deprecated.
|
86
|
+
|
87
|
+
Use {replacement} instead, which is functionally and performance-wise equivalent.
|
88
|
+
"""
|
89
|
+
|
85
90
|
|
86
91
|
def _validate_python_version(
|
87
92
|
python_version: Optional[str], builder_version: ImageBuilderVersion, allow_micro_granularity: bool = True
|
@@ -657,13 +662,16 @@ class _Image(_Object, type_prefix="im"):
|
|
657
662
|
return obj
|
658
663
|
|
659
664
|
def copy_mount(self, mount: _Mount, remote_path: Union[str, Path] = ".") -> "_Image":
|
660
|
-
"""
|
665
|
+
"""
|
666
|
+
**Deprecated**: Use image.add_local_dir(..., copy=True) or similar instead.
|
667
|
+
|
668
|
+
Copy the entire contents of a `modal.Mount` into an image.
|
661
669
|
Useful when files only available locally are required during the image
|
662
670
|
build process.
|
663
671
|
|
664
672
|
**Example**
|
665
673
|
|
666
|
-
```python
|
674
|
+
```python notest
|
667
675
|
static_images_dir = "./static"
|
668
676
|
# place all static images in root of mount
|
669
677
|
mount = modal.Mount.from_local_dir(static_images_dir, remote_path="/")
|
@@ -736,7 +744,6 @@ class _Image(_Object, type_prefix="im"):
|
|
736
744
|
**Usage:**
|
737
745
|
|
738
746
|
```python
|
739
|
-
from pathlib import Path
|
740
747
|
from modal import FilePatternMatcher
|
741
748
|
|
742
749
|
image = modal.Image.debian_slim().add_local_dir(
|
@@ -768,7 +775,7 @@ class _Image(_Object, type_prefix="im"):
|
|
768
775
|
image = modal.Image.debian_slim().add_local_dir(
|
769
776
|
"~/assets",
|
770
777
|
remote_path="/assets",
|
771
|
-
ignore=FilePatternMatcher.from_file(
|
778
|
+
ignore=FilePatternMatcher.from_file("/path/to/ignorefile"),
|
772
779
|
)
|
773
780
|
```
|
774
781
|
"""
|
@@ -786,7 +793,9 @@ class _Image(_Object, type_prefix="im"):
|
|
786
793
|
This works in a similar way to [`COPY`](https://docs.docker.com/engine/reference/builder/#copy)
|
787
794
|
works in a `Dockerfile`.
|
788
795
|
"""
|
789
|
-
|
796
|
+
deprecation_warning(
|
797
|
+
(2024, 1, 13), COPY_DEPRECATION_MESSAGE_PATTERN.format(replacement="image.add_local_file"), pending=True
|
798
|
+
)
|
790
799
|
basename = str(Path(local_path).name)
|
791
800
|
|
792
801
|
def build_dockerfile(version: ImageBuilderVersion) -> DockerfileSpec:
|
@@ -845,14 +854,17 @@ class _Image(_Object, type_prefix="im"):
|
|
845
854
|
# Which follows dockerignore syntax.
|
846
855
|
ignore: Union[Sequence[str], Callable[[Path], bool]] = [],
|
847
856
|
) -> "_Image":
|
848
|
-
"""
|
857
|
+
"""
|
858
|
+
**Deprecated**: Use image.add_local_dir instead
|
859
|
+
|
860
|
+
Copy a directory into the image as a part of building the image.
|
849
861
|
|
850
862
|
This works in a similar way to [`COPY`](https://docs.docker.com/engine/reference/builder/#copy)
|
851
863
|
works in a `Dockerfile`.
|
852
864
|
|
853
865
|
**Usage:**
|
854
866
|
|
855
|
-
```python
|
867
|
+
```python notest
|
856
868
|
from pathlib import Path
|
857
869
|
from modal import FilePatternMatcher
|
858
870
|
|
@@ -885,10 +897,13 @@ class _Image(_Object, type_prefix="im"):
|
|
885
897
|
image = modal.Image.debian_slim().copy_local_dir(
|
886
898
|
"~/assets",
|
887
899
|
remote_path="/assets",
|
888
|
-
ignore=FilePatternMatcher.from_file(
|
900
|
+
ignore=FilePatternMatcher.from_file("/path/to/ignorefile"),
|
889
901
|
)
|
890
902
|
```
|
891
903
|
"""
|
904
|
+
deprecation_warning(
|
905
|
+
(2024, 1, 13), COPY_DEPRECATION_MESSAGE_PATTERN.format(replacement="image.add_local_dir"), pending=True
|
906
|
+
)
|
892
907
|
|
893
908
|
def build_dockerfile(version: ImageBuilderVersion) -> DockerfileSpec:
|
894
909
|
return DockerfileSpec(commands=["FROM base", f"COPY . {remote_path}"], context_files={})
|
@@ -1282,7 +1297,6 @@ class _Image(_Object, type_prefix="im"):
|
|
1282
1297
|
**Usage:**
|
1283
1298
|
|
1284
1299
|
```python
|
1285
|
-
from pathlib import Path
|
1286
1300
|
from modal import FilePatternMatcher
|
1287
1301
|
|
1288
1302
|
# By default a .dockerignore file is used if present in the current working directory
|
@@ -1314,10 +1328,17 @@ class _Image(_Object, type_prefix="im"):
|
|
1314
1328
|
# You can also read ignore patterns from a file.
|
1315
1329
|
image = modal.Image.debian_slim().dockerfile_commands(
|
1316
1330
|
["COPY data /data"],
|
1317
|
-
ignore=FilePatternMatcher.from_file(
|
1331
|
+
ignore=FilePatternMatcher.from_file("/path/to/dockerignore"),
|
1318
1332
|
)
|
1319
1333
|
```
|
1320
1334
|
"""
|
1335
|
+
if context_mount is not None:
|
1336
|
+
deprecation_warning(
|
1337
|
+
(2025, 1, 13),
|
1338
|
+
"`context_mount` is deprecated."
|
1339
|
+
+ " Files are now automatically added to the build context based on the commands.",
|
1340
|
+
pending=True,
|
1341
|
+
)
|
1321
1342
|
cmds = _flatten_str_args("dockerfile_commands", "dockerfile_commands", dockerfile_commands)
|
1322
1343
|
if not cmds:
|
1323
1344
|
return self
|
@@ -1506,7 +1527,8 @@ class _Image(_Object, type_prefix="im"):
|
|
1506
1527
|
"COPY /python/. /usr/local",
|
1507
1528
|
"ENV TERMINFO_DIRS=/etc/terminfo:/lib/terminfo:/usr/share/terminfo:/usr/lib/terminfo",
|
1508
1529
|
]
|
1509
|
-
|
1530
|
+
python_minor = add_python.split(".")[1]
|
1531
|
+
if int(python_minor) < 13:
|
1510
1532
|
# Previous versions did not include the `python` binary, but later ones do.
|
1511
1533
|
# (The important factor is not the Python version itself, but the standalone dist version.)
|
1512
1534
|
# We insert the command in the list at the position it was previously always added
|
@@ -1712,7 +1734,6 @@ class _Image(_Object, type_prefix="im"):
|
|
1712
1734
|
**Usage:**
|
1713
1735
|
|
1714
1736
|
```python
|
1715
|
-
from pathlib import Path
|
1716
1737
|
from modal import FilePatternMatcher
|
1717
1738
|
|
1718
1739
|
# By default a .dockerignore file is used if present in the current working directory
|
@@ -1750,10 +1771,17 @@ class _Image(_Object, type_prefix="im"):
|
|
1750
1771
|
image = modal.Image.from_dockerfile(
|
1751
1772
|
"./Dockerfile",
|
1752
1773
|
add_python="3.12",
|
1753
|
-
ignore=FilePatternMatcher.from_file(
|
1774
|
+
ignore=FilePatternMatcher.from_file("/path/to/dockerignore"),
|
1754
1775
|
)
|
1755
1776
|
```
|
1756
1777
|
"""
|
1778
|
+
if context_mount is not None:
|
1779
|
+
deprecation_warning(
|
1780
|
+
(2025, 1, 13),
|
1781
|
+
"`context_mount` is deprecated."
|
1782
|
+
+ " Files are now automatically added to the build context based on the commands in the Dockerfile.",
|
1783
|
+
pending=True,
|
1784
|
+
)
|
1757
1785
|
|
1758
1786
|
# --- Build the base dockerfile
|
1759
1787
|
|
@@ -2025,11 +2053,11 @@ class _Image(_Object, type_prefix="im"):
|
|
2025
2053
|
try:
|
2026
2054
|
yield
|
2027
2055
|
except Exception as exc:
|
2028
|
-
if self.
|
2029
|
-
# Might be
|
2056
|
+
if not self.is_hydrated:
|
2057
|
+
# Might be hydrated later
|
2030
2058
|
self.inside_exceptions.append(exc)
|
2031
2059
|
elif env_image_id == self.object_id:
|
2032
|
-
# Image is already
|
2060
|
+
# Image is already hydrated (we can remove this case later
|
2033
2061
|
# when we don't hydrate objects so early)
|
2034
2062
|
raise
|
2035
2063
|
if not isinstance(exc, ImportError):
|
@@ -2044,9 +2072,9 @@ class _Image(_Object, type_prefix="im"):
|
|
2044
2072
|
last_entry_id: str = ""
|
2045
2073
|
|
2046
2074
|
request = api_pb2.ImageJoinStreamingRequest(
|
2047
|
-
image_id=self.
|
2075
|
+
image_id=self.object_id, timeout=55, last_entry_id=last_entry_id, include_logs_for_finished=True
|
2048
2076
|
)
|
2049
|
-
async for response in self.
|
2077
|
+
async for response in self.client.stub.ImageJoinStreaming.unary_stream(request):
|
2050
2078
|
if response.result.status:
|
2051
2079
|
return
|
2052
2080
|
if response.entry_id:
|
modal/image.pyi
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
import collections.abc
|
2
2
|
import google.protobuf.message
|
3
|
+
import modal._object
|
3
4
|
import modal.client
|
4
5
|
import modal.cloud_bucket_mount
|
5
6
|
import modal.functions
|
@@ -52,11 +53,11 @@ def _get_image_builder_version(
|
|
52
53
|
) -> typing.Literal["2023.12", "2024.04", "2024.10"]: ...
|
53
54
|
def _create_context_mount(
|
54
55
|
docker_commands: collections.abc.Sequence[str],
|
55
|
-
ignore_fn:
|
56
|
+
ignore_fn: collections.abc.Callable[[pathlib.Path], bool],
|
56
57
|
context_dir: pathlib.Path,
|
57
58
|
) -> typing.Optional[modal.mount._Mount]: ...
|
58
59
|
def _create_context_mount_function(
|
59
|
-
ignore: typing.Union[collections.abc.Sequence[str],
|
60
|
+
ignore: typing.Union[collections.abc.Sequence[str], collections.abc.Callable[[pathlib.Path], bool]],
|
60
61
|
dockerfile_cmds: list[str] = [],
|
61
62
|
dockerfile_path: typing.Optional[pathlib.Path] = None,
|
62
63
|
context_mount: typing.Optional[modal.mount._Mount] = None,
|
@@ -78,7 +79,7 @@ async def _image_await_build_result(
|
|
78
79
|
image_id: str, client: modal.client._Client
|
79
80
|
) -> modal_proto.api_pb2.ImageJoinStreamingResponse: ...
|
80
81
|
|
81
|
-
class _Image(modal.
|
82
|
+
class _Image(modal._object._Object):
|
82
83
|
force_build: bool
|
83
84
|
inside_exceptions: list[Exception]
|
84
85
|
_serve_mounts: frozenset[modal.mount._Mount]
|
@@ -97,14 +98,16 @@ class _Image(modal.object._Object):
|
|
97
98
|
*,
|
98
99
|
base_images: typing.Optional[dict[str, _Image]] = None,
|
99
100
|
dockerfile_function: typing.Optional[
|
100
|
-
|
101
|
+
collections.abc.Callable[[typing.Literal["2023.12", "2024.04", "2024.10"]], DockerfileSpec]
|
101
102
|
] = None,
|
102
103
|
secrets: typing.Optional[collections.abc.Sequence[modal.secret._Secret]] = None,
|
103
104
|
gpu_config: typing.Optional[modal_proto.api_pb2.GPUConfig] = None,
|
104
105
|
build_function: typing.Optional[modal.functions._Function] = None,
|
105
106
|
build_function_input: typing.Optional[modal_proto.api_pb2.FunctionInput] = None,
|
106
107
|
image_registry_config: typing.Optional[_ImageRegistryConfig] = None,
|
107
|
-
context_mount_function: typing.Optional[
|
108
|
+
context_mount_function: typing.Optional[
|
109
|
+
collections.abc.Callable[[], typing.Optional[modal.mount._Mount]]
|
110
|
+
] = None,
|
108
111
|
force_build: bool = False,
|
109
112
|
_namespace: int = 1,
|
110
113
|
_do_assert_no_mount_layers: bool = True,
|
@@ -119,7 +122,7 @@ class _Image(modal.object._Object):
|
|
119
122
|
remote_path: str,
|
120
123
|
*,
|
121
124
|
copy: bool = False,
|
122
|
-
ignore: typing.Union[collections.abc.Sequence[str],
|
125
|
+
ignore: typing.Union[collections.abc.Sequence[str], collections.abc.Callable[[pathlib.Path], bool]] = [],
|
123
126
|
) -> _Image: ...
|
124
127
|
def copy_local_file(
|
125
128
|
self, local_path: typing.Union[str, pathlib.Path], remote_path: typing.Union[str, pathlib.Path] = "./"
|
@@ -129,14 +132,14 @@ class _Image(modal.object._Object):
|
|
129
132
|
*module_names: str,
|
130
133
|
copy: bool = False,
|
131
134
|
ignore: typing.Union[
|
132
|
-
collections.abc.Sequence[str],
|
135
|
+
collections.abc.Sequence[str], collections.abc.Callable[[pathlib.Path], bool]
|
133
136
|
] = modal.file_pattern_matcher.NON_PYTHON_FILES,
|
134
137
|
) -> _Image: ...
|
135
138
|
def copy_local_dir(
|
136
139
|
self,
|
137
140
|
local_path: typing.Union[str, pathlib.Path],
|
138
141
|
remote_path: typing.Union[str, pathlib.Path] = ".",
|
139
|
-
ignore: typing.Union[collections.abc.Sequence[str],
|
142
|
+
ignore: typing.Union[collections.abc.Sequence[str], collections.abc.Callable[[pathlib.Path], bool]] = [],
|
140
143
|
) -> _Image: ...
|
141
144
|
@staticmethod
|
142
145
|
async def from_id(image_id: str, client: typing.Optional[modal.client._Client] = None) -> _Image: ...
|
@@ -215,7 +218,7 @@ class _Image(modal.object._Object):
|
|
215
218
|
context_mount: typing.Optional[modal.mount._Mount] = None,
|
216
219
|
force_build: bool = False,
|
217
220
|
ignore: typing.Union[
|
218
|
-
collections.abc.Sequence[str],
|
221
|
+
collections.abc.Sequence[str], collections.abc.Callable[[pathlib.Path], bool]
|
219
222
|
] = modal.image.AUTO_DOCKERIGNORE,
|
220
223
|
) -> _Image: ...
|
221
224
|
def entrypoint(self, entrypoint_commands: list[str]) -> _Image: ...
|
@@ -303,7 +306,7 @@ class _Image(modal.object._Object):
|
|
303
306
|
gpu: typing.Union[None, bool, str, modal.gpu._GPUConfig] = None,
|
304
307
|
add_python: typing.Optional[str] = None,
|
305
308
|
ignore: typing.Union[
|
306
|
-
collections.abc.Sequence[str],
|
309
|
+
collections.abc.Sequence[str], collections.abc.Callable[[pathlib.Path], bool]
|
307
310
|
] = modal.image.AUTO_DOCKERIGNORE,
|
308
311
|
) -> _Image: ...
|
309
312
|
@staticmethod
|
@@ -317,7 +320,7 @@ class _Image(modal.object._Object):
|
|
317
320
|
) -> _Image: ...
|
318
321
|
def run_function(
|
319
322
|
self,
|
320
|
-
raw_f:
|
323
|
+
raw_f: collections.abc.Callable[..., typing.Any],
|
321
324
|
secrets: collections.abc.Sequence[modal.secret._Secret] = (),
|
322
325
|
gpu: typing.Union[
|
323
326
|
None, bool, str, modal.gpu._GPUConfig, list[typing.Union[None, bool, str, modal.gpu._GPUConfig]]
|
@@ -344,6 +347,8 @@ class _Image(modal.object._Object):
|
|
344
347
|
def imports(self): ...
|
345
348
|
def _logs(self) -> typing.AsyncGenerator[str, None]: ...
|
346
349
|
|
350
|
+
SUPERSELF = typing.TypeVar("SUPERSELF", covariant=True)
|
351
|
+
|
347
352
|
class Image(modal.object.Object):
|
348
353
|
force_build: bool
|
349
354
|
inside_exceptions: list[Exception]
|
@@ -364,14 +369,16 @@ class Image(modal.object.Object):
|
|
364
369
|
*,
|
365
370
|
base_images: typing.Optional[dict[str, Image]] = None,
|
366
371
|
dockerfile_function: typing.Optional[
|
367
|
-
|
372
|
+
collections.abc.Callable[[typing.Literal["2023.12", "2024.04", "2024.10"]], DockerfileSpec]
|
368
373
|
] = None,
|
369
374
|
secrets: typing.Optional[collections.abc.Sequence[modal.secret.Secret]] = None,
|
370
375
|
gpu_config: typing.Optional[modal_proto.api_pb2.GPUConfig] = None,
|
371
376
|
build_function: typing.Optional[modal.functions.Function] = None,
|
372
377
|
build_function_input: typing.Optional[modal_proto.api_pb2.FunctionInput] = None,
|
373
378
|
image_registry_config: typing.Optional[_ImageRegistryConfig] = None,
|
374
|
-
context_mount_function: typing.Optional[
|
379
|
+
context_mount_function: typing.Optional[
|
380
|
+
collections.abc.Callable[[], typing.Optional[modal.mount.Mount]]
|
381
|
+
] = None,
|
375
382
|
force_build: bool = False,
|
376
383
|
_namespace: int = 1,
|
377
384
|
_do_assert_no_mount_layers: bool = True,
|
@@ -386,7 +393,7 @@ class Image(modal.object.Object):
|
|
386
393
|
remote_path: str,
|
387
394
|
*,
|
388
395
|
copy: bool = False,
|
389
|
-
ignore: typing.Union[collections.abc.Sequence[str],
|
396
|
+
ignore: typing.Union[collections.abc.Sequence[str], collections.abc.Callable[[pathlib.Path], bool]] = [],
|
390
397
|
) -> Image: ...
|
391
398
|
def copy_local_file(
|
392
399
|
self, local_path: typing.Union[str, pathlib.Path], remote_path: typing.Union[str, pathlib.Path] = "./"
|
@@ -396,14 +403,14 @@ class Image(modal.object.Object):
|
|
396
403
|
*module_names: str,
|
397
404
|
copy: bool = False,
|
398
405
|
ignore: typing.Union[
|
399
|
-
collections.abc.Sequence[str],
|
406
|
+
collections.abc.Sequence[str], collections.abc.Callable[[pathlib.Path], bool]
|
400
407
|
] = modal.file_pattern_matcher.NON_PYTHON_FILES,
|
401
408
|
) -> Image: ...
|
402
409
|
def copy_local_dir(
|
403
410
|
self,
|
404
411
|
local_path: typing.Union[str, pathlib.Path],
|
405
412
|
remote_path: typing.Union[str, pathlib.Path] = ".",
|
406
|
-
ignore: typing.Union[collections.abc.Sequence[str],
|
413
|
+
ignore: typing.Union[collections.abc.Sequence[str], collections.abc.Callable[[pathlib.Path], bool]] = [],
|
407
414
|
) -> Image: ...
|
408
415
|
|
409
416
|
class __from_id_spec(typing_extensions.Protocol):
|
@@ -487,7 +494,7 @@ class Image(modal.object.Object):
|
|
487
494
|
context_mount: typing.Optional[modal.mount.Mount] = None,
|
488
495
|
force_build: bool = False,
|
489
496
|
ignore: typing.Union[
|
490
|
-
collections.abc.Sequence[str],
|
497
|
+
collections.abc.Sequence[str], collections.abc.Callable[[pathlib.Path], bool]
|
491
498
|
] = modal.image.AUTO_DOCKERIGNORE,
|
492
499
|
) -> Image: ...
|
493
500
|
def entrypoint(self, entrypoint_commands: list[str]) -> Image: ...
|
@@ -575,7 +582,7 @@ class Image(modal.object.Object):
|
|
575
582
|
gpu: typing.Union[None, bool, str, modal.gpu._GPUConfig] = None,
|
576
583
|
add_python: typing.Optional[str] = None,
|
577
584
|
ignore: typing.Union[
|
578
|
-
collections.abc.Sequence[str],
|
585
|
+
collections.abc.Sequence[str], collections.abc.Callable[[pathlib.Path], bool]
|
579
586
|
] = modal.image.AUTO_DOCKERIGNORE,
|
580
587
|
) -> Image: ...
|
581
588
|
@staticmethod
|
@@ -589,7 +596,7 @@ class Image(modal.object.Object):
|
|
589
596
|
) -> Image: ...
|
590
597
|
def run_function(
|
591
598
|
self,
|
592
|
-
raw_f:
|
599
|
+
raw_f: collections.abc.Callable[..., typing.Any],
|
593
600
|
secrets: collections.abc.Sequence[modal.secret.Secret] = (),
|
594
601
|
gpu: typing.Union[
|
595
602
|
None, bool, str, modal.gpu._GPUConfig, list[typing.Union[None, bool, str, modal.gpu._GPUConfig]]
|
@@ -615,10 +622,10 @@ class Image(modal.object.Object):
|
|
615
622
|
def workdir(self, path: typing.Union[str, pathlib.PurePosixPath]) -> Image: ...
|
616
623
|
def imports(self): ...
|
617
624
|
|
618
|
-
class ___logs_spec(typing_extensions.Protocol):
|
625
|
+
class ___logs_spec(typing_extensions.Protocol[SUPERSELF]):
|
619
626
|
def __call__(self) -> typing.Generator[str, None, None]: ...
|
620
627
|
def aio(self) -> typing.AsyncGenerator[str, None]: ...
|
621
628
|
|
622
|
-
_logs: ___logs_spec
|
629
|
+
_logs: ___logs_spec[typing_extensions.Self]
|
623
630
|
|
624
631
|
SUPPORTED_PYTHON_SERIES: dict[typing.Literal["2023.12", "2024.04", "2024.10"], list[str]]
|
modal/io_streams.pyi
CHANGED
@@ -50,6 +50,8 @@ class _StreamWriter:
|
|
50
50
|
|
51
51
|
T_INNER = typing.TypeVar("T_INNER", covariant=True)
|
52
52
|
|
53
|
+
SUPERSELF = typing.TypeVar("SUPERSELF", covariant=True)
|
54
|
+
|
53
55
|
class StreamReader(typing.Generic[T]):
|
54
56
|
_stream: typing.Optional[collections.abc.AsyncGenerator[typing.Optional[bytes], None]]
|
55
57
|
|
@@ -66,25 +68,25 @@ class StreamReader(typing.Generic[T]):
|
|
66
68
|
@property
|
67
69
|
def file_descriptor(self) -> int: ...
|
68
70
|
|
69
|
-
class __read_spec(typing_extensions.Protocol[T_INNER]):
|
71
|
+
class __read_spec(typing_extensions.Protocol[T_INNER, SUPERSELF]):
|
70
72
|
def __call__(self) -> T_INNER: ...
|
71
73
|
async def aio(self) -> T_INNER: ...
|
72
74
|
|
73
|
-
read: __read_spec[T]
|
75
|
+
read: __read_spec[T, typing_extensions.Self]
|
74
76
|
|
75
|
-
class ___consume_container_process_stream_spec(typing_extensions.Protocol):
|
77
|
+
class ___consume_container_process_stream_spec(typing_extensions.Protocol[SUPERSELF]):
|
76
78
|
def __call__(self): ...
|
77
79
|
async def aio(self): ...
|
78
80
|
|
79
|
-
_consume_container_process_stream: ___consume_container_process_stream_spec
|
81
|
+
_consume_container_process_stream: ___consume_container_process_stream_spec[typing_extensions.Self]
|
80
82
|
|
81
|
-
class ___stream_container_process_spec(typing_extensions.Protocol):
|
83
|
+
class ___stream_container_process_spec(typing_extensions.Protocol[SUPERSELF]):
|
82
84
|
def __call__(self) -> typing.Generator[tuple[typing.Optional[bytes], str], None, None]: ...
|
83
85
|
def aio(self) -> collections.abc.AsyncGenerator[tuple[typing.Optional[bytes], str], None]: ...
|
84
86
|
|
85
|
-
_stream_container_process: ___stream_container_process_spec
|
87
|
+
_stream_container_process: ___stream_container_process_spec[typing_extensions.Self]
|
86
88
|
|
87
|
-
class ___get_logs_spec(typing_extensions.Protocol):
|
89
|
+
class ___get_logs_spec(typing_extensions.Protocol[SUPERSELF]):
|
88
90
|
def __call__(
|
89
91
|
self, skip_empty_messages: bool = True
|
90
92
|
) -> typing.Generator[typing.Optional[bytes], None, None]: ...
|
@@ -92,13 +94,13 @@ class StreamReader(typing.Generic[T]):
|
|
92
94
|
self, skip_empty_messages: bool = True
|
93
95
|
) -> collections.abc.AsyncGenerator[typing.Optional[bytes], None]: ...
|
94
96
|
|
95
|
-
_get_logs: ___get_logs_spec
|
97
|
+
_get_logs: ___get_logs_spec[typing_extensions.Self]
|
96
98
|
|
97
|
-
class ___get_logs_by_line_spec(typing_extensions.Protocol):
|
99
|
+
class ___get_logs_by_line_spec(typing_extensions.Protocol[SUPERSELF]):
|
98
100
|
def __call__(self) -> typing.Generator[typing.Optional[bytes], None, None]: ...
|
99
101
|
def aio(self) -> collections.abc.AsyncGenerator[typing.Optional[bytes], None]: ...
|
100
102
|
|
101
|
-
_get_logs_by_line: ___get_logs_by_line_spec
|
103
|
+
_get_logs_by_line: ___get_logs_by_line_spec[typing_extensions.Self]
|
102
104
|
|
103
105
|
def __iter__(self) -> typing.Iterator[T]: ...
|
104
106
|
def __aiter__(self) -> collections.abc.AsyncIterator[T]: ...
|
@@ -115,8 +117,8 @@ class StreamWriter:
|
|
115
117
|
def write(self, data: typing.Union[bytes, bytearray, memoryview, str]) -> None: ...
|
116
118
|
def write_eof(self) -> None: ...
|
117
119
|
|
118
|
-
class __drain_spec(typing_extensions.Protocol):
|
120
|
+
class __drain_spec(typing_extensions.Protocol[SUPERSELF]):
|
119
121
|
def __call__(self) -> None: ...
|
120
122
|
async def aio(self) -> None: ...
|
121
123
|
|
122
|
-
drain: __drain_spec
|
124
|
+
drain: __drain_spec[typing_extensions.Self]
|
modal/mount.py
CHANGED
@@ -20,6 +20,7 @@ import modal.file_pattern_matcher
|
|
20
20
|
from modal_proto import api_pb2
|
21
21
|
from modal_version import __version__
|
22
22
|
|
23
|
+
from ._object import _get_environment_name, _Object
|
23
24
|
from ._resolver import Resolver
|
24
25
|
from ._utils.async_utils import aclosing, async_map, synchronize_api
|
25
26
|
from ._utils.blob_utils import FileUploadSpec, blob_upload_file, get_file_upload_spec_from_path
|
@@ -31,7 +32,6 @@ from .client import _Client
|
|
31
32
|
from .config import config, logger
|
32
33
|
from .exception import InvalidError, ModuleNotMountable
|
33
34
|
from .file_pattern_matcher import FilePatternMatcher
|
34
|
-
from .object import _get_environment_name, _Object
|
35
35
|
|
36
36
|
ROOT_DIR: PurePosixPath = PurePosixPath("/root")
|
37
37
|
MOUNT_PUT_FILE_CLIENT_TIMEOUT = 10 * 60 # 10 min max for transferring files
|
@@ -258,12 +258,15 @@ class NonLocalMountError(Exception):
|
|
258
258
|
|
259
259
|
|
260
260
|
class _Mount(_Object, type_prefix="mo"):
|
261
|
-
"""
|
261
|
+
"""
|
262
|
+
**Deprecated**: Mounts should not be used explicitly anymore, use `Image.add_local_*` commands instead.
|
263
|
+
|
264
|
+
Create a mount for a local directory or file that can be attached
|
262
265
|
to one or more Modal functions.
|
263
266
|
|
264
267
|
**Usage**
|
265
268
|
|
266
|
-
```python
|
269
|
+
```python notest
|
267
270
|
import modal
|
268
271
|
import os
|
269
272
|
app = modal.App()
|
@@ -394,11 +397,13 @@ class _Mount(_Object, type_prefix="mo"):
|
|
394
397
|
recursive: bool = True,
|
395
398
|
) -> "_Mount":
|
396
399
|
"""
|
400
|
+
**Deprecated:** Use image.add_local_dir() instead
|
401
|
+
|
397
402
|
Create a `Mount` from a local directory.
|
398
403
|
|
399
404
|
**Usage**
|
400
405
|
|
401
|
-
```python
|
406
|
+
```python notest
|
402
407
|
assets = modal.Mount.from_local_dir(
|
403
408
|
"~/assets",
|
404
409
|
condition=lambda pth: not ".venv" in pth,
|
@@ -449,11 +454,13 @@ class _Mount(_Object, type_prefix="mo"):
|
|
449
454
|
@staticmethod
|
450
455
|
def from_local_file(local_path: Union[str, Path], remote_path: Union[str, PurePosixPath, None] = None) -> "_Mount":
|
451
456
|
"""
|
457
|
+
**Deprecated**: Use image.add_local_file() instead
|
458
|
+
|
452
459
|
Create a `Mount` mounting a single local file.
|
453
460
|
|
454
461
|
**Usage**
|
455
462
|
|
456
|
-
```python
|
463
|
+
```python notest
|
457
464
|
# Mount the DBT profile in user's home directory into container.
|
458
465
|
dbt_profiles = modal.Mount.from_local_file(
|
459
466
|
local_path="~/profiles.yml",
|
@@ -611,6 +618,8 @@ class _Mount(_Object, type_prefix="mo"):
|
|
611
618
|
ignore: Optional[Union[Sequence[str], Callable[[Path], bool]]] = None,
|
612
619
|
) -> "_Mount":
|
613
620
|
"""
|
621
|
+
**Deprecated**: Use image.add_local_python_source instead
|
622
|
+
|
614
623
|
Returns a `modal.Mount` that makes local modules listed in `module_names` available inside the container.
|
615
624
|
This works by mounting the local path of each module's package to a directory inside the container
|
616
625
|
that's on `PYTHONPATH`.
|