modal 0.71.12__py3-none-any.whl → 0.71.13__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/client.pyi +2 -2
- modal/file_pattern_matcher.py +43 -18
- modal/functions.pyi +6 -6
- modal/image.py +90 -5
- {modal-0.71.12.dist-info → modal-0.71.13.dist-info}/METADATA +1 -1
- {modal-0.71.12.dist-info → modal-0.71.13.dist-info}/RECORD +11 -11
- modal_version/_version_generated.py +1 -1
- {modal-0.71.12.dist-info → modal-0.71.13.dist-info}/LICENSE +0 -0
- {modal-0.71.12.dist-info → modal-0.71.13.dist-info}/WHEEL +0 -0
- {modal-0.71.12.dist-info → modal-0.71.13.dist-info}/entry_points.txt +0 -0
- {modal-0.71.12.dist-info → modal-0.71.13.dist-info}/top_level.txt +0 -0
modal/client.pyi
CHANGED
@@ -26,7 +26,7 @@ class _Client:
|
|
26
26
|
_stub: typing.Optional[modal_proto.api_grpc.ModalClientStub]
|
27
27
|
|
28
28
|
def __init__(
|
29
|
-
self, server_url: str, client_type: int, credentials: typing.Optional[tuple[str, str]], version: str = "0.71.
|
29
|
+
self, server_url: str, client_type: int, credentials: typing.Optional[tuple[str, str]], version: str = "0.71.13"
|
30
30
|
): ...
|
31
31
|
def is_closed(self) -> bool: ...
|
32
32
|
@property
|
@@ -81,7 +81,7 @@ class Client:
|
|
81
81
|
_stub: typing.Optional[modal_proto.api_grpc.ModalClientStub]
|
82
82
|
|
83
83
|
def __init__(
|
84
|
-
self, server_url: str, client_type: int, credentials: typing.Optional[tuple[str, str]], version: str = "0.71.
|
84
|
+
self, server_url: str, client_type: int, credentials: typing.Optional[tuple[str, str]], version: str = "0.71.13"
|
85
85
|
): ...
|
86
86
|
def is_closed(self) -> bool: ...
|
87
87
|
@property
|
modal/file_pattern_matcher.py
CHANGED
@@ -62,6 +62,27 @@ class _CustomPatternMatcher(_AbstractPatternMatcher):
|
|
62
62
|
class FilePatternMatcher(_AbstractPatternMatcher):
|
63
63
|
"""Allows matching file paths against a list of patterns."""
|
64
64
|
|
65
|
+
patterns: list[Pattern]
|
66
|
+
_delayed_init: Callable[[], None] = None
|
67
|
+
|
68
|
+
def _set_patterns(self, patterns: Sequence[str]) -> None:
|
69
|
+
self.patterns = []
|
70
|
+
for pattern in list(patterns):
|
71
|
+
pattern = pattern.strip()
|
72
|
+
if not pattern:
|
73
|
+
continue
|
74
|
+
pattern = os.path.normpath(pattern)
|
75
|
+
new_pattern = Pattern()
|
76
|
+
if pattern[0] == "!":
|
77
|
+
if len(pattern) == 1:
|
78
|
+
raise ValueError('Illegal exclusion pattern: "!"')
|
79
|
+
new_pattern.exclusion = True
|
80
|
+
pattern = pattern[1:]
|
81
|
+
# In Python, we can proceed without explicit syntax checking
|
82
|
+
new_pattern.cleaned_pattern = pattern
|
83
|
+
new_pattern.dirs = pattern.split(os.path.sep)
|
84
|
+
self.patterns.append(new_pattern)
|
85
|
+
|
65
86
|
def __init__(self, *pattern: str) -> None:
|
66
87
|
"""Initialize a new FilePatternMatcher instance.
|
67
88
|
|
@@ -71,24 +92,25 @@ class FilePatternMatcher(_AbstractPatternMatcher):
|
|
71
92
|
Raises:
|
72
93
|
ValueError: If an illegal exclusion pattern is provided.
|
73
94
|
"""
|
74
|
-
self.
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
95
|
+
self._set_patterns(pattern)
|
96
|
+
|
97
|
+
@classmethod
|
98
|
+
def from_file(cls, file_path: Path) -> "FilePatternMatcher":
|
99
|
+
"""Initialize a new FilePatternMatcher instance from a file.
|
100
|
+
|
101
|
+
The patterns in the file will be read lazily when the matcher is first used.
|
102
|
+
|
103
|
+
Args:
|
104
|
+
file_path (Path): The path to the file containing patterns.
|
105
|
+
"""
|
106
|
+
uninitialized = cls.__new__(cls)
|
107
|
+
|
108
|
+
def _delayed_init():
|
109
|
+
uninitialized._set_patterns(file_path.read_text("utf8").splitlines())
|
110
|
+
uninitialized._delayed_init = None
|
111
|
+
|
112
|
+
uninitialized._delayed_init = _delayed_init
|
113
|
+
return uninitialized
|
92
114
|
|
93
115
|
def _matches(self, file_path: str) -> bool:
|
94
116
|
"""Check if the file path or any of its parent directories match the patterns.
|
@@ -97,6 +119,7 @@ class FilePatternMatcher(_AbstractPatternMatcher):
|
|
97
119
|
library. The reason is that `Matches()` in the original library is
|
98
120
|
deprecated due to buggy behavior.
|
99
121
|
"""
|
122
|
+
|
100
123
|
matched = False
|
101
124
|
file_path = os.path.normpath(file_path)
|
102
125
|
if file_path == ".":
|
@@ -146,6 +169,8 @@ class FilePatternMatcher(_AbstractPatternMatcher):
|
|
146
169
|
assert matcher(Path("foo.py"))
|
147
170
|
```
|
148
171
|
"""
|
172
|
+
if self._delayed_init:
|
173
|
+
self._delayed_init()
|
149
174
|
return self._matches(str(file_path))
|
150
175
|
|
151
176
|
|
modal/functions.pyi
CHANGED
@@ -462,11 +462,11 @@ class Function(typing.Generic[P, ReturnType, OriginalReturnType], modal.object.O
|
|
462
462
|
|
463
463
|
_call_generator_nowait: ___call_generator_nowait_spec
|
464
464
|
|
465
|
-
class __remote_spec(typing_extensions.Protocol[
|
465
|
+
class __remote_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER]):
|
466
466
|
def __call__(self, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> ReturnType_INNER: ...
|
467
467
|
async def aio(self, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> ReturnType_INNER: ...
|
468
468
|
|
469
|
-
remote: __remote_spec[
|
469
|
+
remote: __remote_spec[P, ReturnType]
|
470
470
|
|
471
471
|
class __remote_gen_spec(typing_extensions.Protocol):
|
472
472
|
def __call__(self, *args, **kwargs) -> typing.Generator[typing.Any, None, None]: ...
|
@@ -479,17 +479,17 @@ class Function(typing.Generic[P, ReturnType, OriginalReturnType], modal.object.O
|
|
479
479
|
def _get_obj(self) -> typing.Optional[modal.cls.Obj]: ...
|
480
480
|
def local(self, *args: P.args, **kwargs: P.kwargs) -> OriginalReturnType: ...
|
481
481
|
|
482
|
-
class ___experimental_spawn_spec(typing_extensions.Protocol[
|
482
|
+
class ___experimental_spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER]):
|
483
483
|
def __call__(self, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]: ...
|
484
484
|
async def aio(self, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]: ...
|
485
485
|
|
486
|
-
_experimental_spawn: ___experimental_spawn_spec[
|
486
|
+
_experimental_spawn: ___experimental_spawn_spec[P, ReturnType]
|
487
487
|
|
488
|
-
class __spawn_spec(typing_extensions.Protocol[
|
488
|
+
class __spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER]):
|
489
489
|
def __call__(self, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]: ...
|
490
490
|
async def aio(self, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]: ...
|
491
491
|
|
492
|
-
spawn: __spawn_spec[
|
492
|
+
spawn: __spawn_spec[P, ReturnType]
|
493
493
|
|
494
494
|
def get_raw_f(self) -> typing.Callable[..., typing.Any]: ...
|
495
495
|
|
modal/image.py
CHANGED
@@ -683,6 +683,7 @@ class _Image(_Object, type_prefix="im"):
|
|
683
683
|
**Usage:**
|
684
684
|
|
685
685
|
```python
|
686
|
+
from pathlib import Path
|
686
687
|
from modal import FilePatternMatcher
|
687
688
|
|
688
689
|
image = modal.Image.debian_slim().add_local_dir(
|
@@ -697,18 +698,25 @@ class _Image(_Object, type_prefix="im"):
|
|
697
698
|
ignore=lambda p: p.is_relative_to(".venv"),
|
698
699
|
)
|
699
700
|
|
700
|
-
image = modal.Image.debian_slim().
|
701
|
+
image = modal.Image.debian_slim().add_local_dir(
|
701
702
|
"~/assets",
|
702
703
|
remote_path="/assets",
|
703
704
|
ignore=FilePatternMatcher("**/*.txt"),
|
704
705
|
)
|
705
706
|
|
706
707
|
# When including files is simpler than excluding them, you can use the `~` operator to invert the matcher.
|
707
|
-
image = modal.Image.debian_slim().
|
708
|
+
image = modal.Image.debian_slim().add_local_dir(
|
708
709
|
"~/assets",
|
709
710
|
remote_path="/assets",
|
710
711
|
ignore=~FilePatternMatcher("**/*.py"),
|
711
712
|
)
|
713
|
+
|
714
|
+
# You can also read ignore patterns from a file.
|
715
|
+
image = modal.Image.debian_slim().add_local_dir(
|
716
|
+
"~/assets",
|
717
|
+
remote_path="/assets",
|
718
|
+
ignore=FilePatternMatcher.from_file(Path("/path/to/ignorefile")),
|
719
|
+
)
|
712
720
|
```
|
713
721
|
"""
|
714
722
|
if not PurePosixPath(remote_path).is_absolute():
|
@@ -792,6 +800,7 @@ class _Image(_Object, type_prefix="im"):
|
|
792
800
|
**Usage:**
|
793
801
|
|
794
802
|
```python
|
803
|
+
from pathlib import Path
|
795
804
|
from modal import FilePatternMatcher
|
796
805
|
|
797
806
|
image = modal.Image.debian_slim().copy_local_dir(
|
@@ -818,6 +827,13 @@ class _Image(_Object, type_prefix="im"):
|
|
818
827
|
remote_path="/assets",
|
819
828
|
ignore=~FilePatternMatcher("**/*.py"),
|
820
829
|
)
|
830
|
+
|
831
|
+
# You can also read ignore patterns from a file.
|
832
|
+
image = modal.Image.debian_slim().copy_local_dir(
|
833
|
+
"~/assets",
|
834
|
+
remote_path="/assets",
|
835
|
+
ignore=FilePatternMatcher.from_file(Path("/path/to/ignorefile")),
|
836
|
+
)
|
821
837
|
```
|
822
838
|
"""
|
823
839
|
|
@@ -1207,7 +1223,43 @@ class _Image(_Object, type_prefix="im"):
|
|
1207
1223
|
force_build: bool = False, # Ignore cached builds, similar to 'docker build --no-cache'
|
1208
1224
|
ignore: Union[Sequence[str], Callable[[Path], bool]] = (),
|
1209
1225
|
) -> "_Image":
|
1210
|
-
"""
|
1226
|
+
"""
|
1227
|
+
Extend an image with arbitrary Dockerfile-like commands.
|
1228
|
+
|
1229
|
+
**Usage:**
|
1230
|
+
|
1231
|
+
```python
|
1232
|
+
from pathlib import Path
|
1233
|
+
from modal import FilePatternMatcher
|
1234
|
+
|
1235
|
+
image = modal.Image.debian_slim().dockerfile_commands(
|
1236
|
+
["COPY data /data"],
|
1237
|
+
ignore=["*.venv"],
|
1238
|
+
)
|
1239
|
+
|
1240
|
+
image = modal.Image.debian_slim().dockerfile_commands(
|
1241
|
+
["COPY data /data"],
|
1242
|
+
ignore=lambda p: p.is_relative_to(".venv"),
|
1243
|
+
)
|
1244
|
+
|
1245
|
+
image = modal.Image.debian_slim().dockerfile_commands(
|
1246
|
+
["COPY data /data"],
|
1247
|
+
ignore=FilePatternMatcher("**/*.txt"),
|
1248
|
+
)
|
1249
|
+
|
1250
|
+
# When including files is simpler than excluding them, you can use the `~` operator to invert the matcher.
|
1251
|
+
image = modal.Image.debian_slim().dockerfile_commands(
|
1252
|
+
["COPY data /data"],
|
1253
|
+
ignore=~FilePatternMatcher("**/*.py"),
|
1254
|
+
)
|
1255
|
+
|
1256
|
+
# You can also read ignore patterns from a file.
|
1257
|
+
image = modal.Image.debian_slim().dockerfile_commands(
|
1258
|
+
["COPY data /data"],
|
1259
|
+
ignore=FilePatternMatcher.from_file(Path("/path/to/dockerignore")),
|
1260
|
+
)
|
1261
|
+
```
|
1262
|
+
"""
|
1211
1263
|
cmds = _flatten_str_args("dockerfile_commands", "dockerfile_commands", dockerfile_commands)
|
1212
1264
|
if not cmds:
|
1213
1265
|
return self
|
@@ -1608,10 +1660,43 @@ class _Image(_Object, type_prefix="im"):
|
|
1608
1660
|
If your Dockerfile does not have Python installed, you can use the `add_python` parameter
|
1609
1661
|
to specify a version of Python to add to the image.
|
1610
1662
|
|
1611
|
-
**
|
1663
|
+
**Usage:**
|
1612
1664
|
|
1613
1665
|
```python
|
1614
|
-
|
1666
|
+
from pathlib import Path
|
1667
|
+
from modal import FilePatternMatcher
|
1668
|
+
|
1669
|
+
image = modal.Image.from_dockerfile(
|
1670
|
+
"./Dockerfile",
|
1671
|
+
add_python="3.12",
|
1672
|
+
ignore=["*.venv"],
|
1673
|
+
)
|
1674
|
+
|
1675
|
+
image = modal.Image.from_dockerfile(
|
1676
|
+
"./Dockerfile",
|
1677
|
+
add_python="3.12",
|
1678
|
+
ignore=lambda p: p.is_relative_to(".venv"),
|
1679
|
+
)
|
1680
|
+
|
1681
|
+
image = modal.Image.from_dockerfile(
|
1682
|
+
"./Dockerfile",
|
1683
|
+
add_python="3.12",
|
1684
|
+
ignore=FilePatternMatcher("**/*.txt"),
|
1685
|
+
)
|
1686
|
+
|
1687
|
+
# When including files is simpler than excluding them, you can use the `~` operator to invert the matcher.
|
1688
|
+
image = modal.Image.from_dockerfile(
|
1689
|
+
"./Dockerfile",
|
1690
|
+
add_python="3.12",
|
1691
|
+
ignore=~FilePatternMatcher("**/*.py"),
|
1692
|
+
)
|
1693
|
+
|
1694
|
+
# You can also read ignore patterns from a file.
|
1695
|
+
image = modal.Image.from_dockerfile(
|
1696
|
+
"./Dockerfile",
|
1697
|
+
add_python="3.12",
|
1698
|
+
ignore=FilePatternMatcher.from_file(Path("/path/to/dockerignore")),
|
1699
|
+
)
|
1615
1700
|
```
|
1616
1701
|
"""
|
1617
1702
|
|
@@ -19,7 +19,7 @@ modal/app.py,sha256=vEE0cK5QPF6_cdW5AJvcuWxz5KmeprHwBEtlDkVRHgE,45582
|
|
19
19
|
modal/app.pyi,sha256=Gx7gxjfQ70sxhbwfpx1VjvzEON-ZEMTJ_Vy8qt0oQvo,25302
|
20
20
|
modal/call_graph.py,sha256=1g2DGcMIJvRy-xKicuf63IVE98gJSnQsr8R_NVMptNc,2581
|
21
21
|
modal/client.py,sha256=JAnd4-GCN093BwkvOFAK5a6iy5ycxofjpUncMxlrIMw,15253
|
22
|
-
modal/client.pyi,sha256=
|
22
|
+
modal/client.pyi,sha256=8J3-EAE51lpcCOdLSSKFWuC3NhItuXhgxIv5NXpy4_0,7280
|
23
23
|
modal/cloud_bucket_mount.py,sha256=G7T7jWLD0QkmrfKR75mSTwdUZ2xNfj7pkVqb4ipmxmI,5735
|
24
24
|
modal/cloud_bucket_mount.pyi,sha256=CEi7vrH3kDUF4LAy4qP6tfImy2UJuFRcRbsgRNM1wo8,1403
|
25
25
|
modal/cls.py,sha256=3hjb0JcoPjxKZNeK22f5rR43bZRBjoRI7_EMZXY7YrE,31172
|
@@ -35,11 +35,11 @@ modal/exception.py,sha256=4JyO-SACaLNDe2QC48EjsK8GMkZ8AgEurZ8j1YdRu8E,5263
|
|
35
35
|
modal/experimental.py,sha256=npfKbyMpI41uZZs9HW_QiB3E4ykWfDXZbACXXbw6qeA,2385
|
36
36
|
modal/file_io.py,sha256=lcMs_E9Xfm0YX1t9U2wNIBPnqHRxmImqjLW1GHqVmyg,20945
|
37
37
|
modal/file_io.pyi,sha256=NrIoB0YjIqZ8MDMe826xAnybT0ww_kxQM3iPLo82REU,8898
|
38
|
-
modal/file_pattern_matcher.py,sha256=
|
38
|
+
modal/file_pattern_matcher.py,sha256=uksEpQG4LSNdW57NQVqP9oOWPpD2-c9QVaAN_dmzKIQ,6415
|
39
39
|
modal/functions.py,sha256=3uJPbrEAWhpFfLfUnoRjGmvEUC-_wVh-8yNJBx8eVeM,68249
|
40
|
-
modal/functions.pyi,sha256=
|
40
|
+
modal/functions.pyi,sha256=LiSDgH-X7jcZ56pAoLMwo3x9Dzdp_3Sd7W5MVAJPoCg,25407
|
41
41
|
modal/gpu.py,sha256=MTxj6ql8EpgfBg8YmZ5a1cLznyuZFssX1qXbEX4LKVM,7503
|
42
|
-
modal/image.py,sha256=
|
42
|
+
modal/image.py,sha256=l1qJRQwkeD1Fq5KWY80ZwNyxpcEJwA92fbrAizBRtdk,87985
|
43
43
|
modal/image.pyi,sha256=Pa1_LVr3FyNsnu_MhBO08fBgCeLazTEe25phYdu0bzE,25365
|
44
44
|
modal/io_streams.py,sha256=QkQiizKRzd5bnbKQsap31LJgBYlAnj4-XkV_50xPYX0,15079
|
45
45
|
modal/io_streams.pyi,sha256=bCCVSxkMcosYd8O3PQDDwJw7TQ8JEcnYonLJ5t27TQs,4804
|
@@ -165,10 +165,10 @@ modal_proto/options_pb2_grpc.pyi,sha256=CImmhxHsYnF09iENPoe8S4J-n93jtgUYD2JPAc0y
|
|
165
165
|
modal_proto/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
166
166
|
modal_version/__init__.py,sha256=BEBWj9tcbFUwzEjUrqly601rauw5cYsHdcmJHs3iu0s,470
|
167
167
|
modal_version/__main__.py,sha256=2FO0yYQQwDTh6udt1h-cBnGd1c4ZyHnHSI4BksxzVac,105
|
168
|
-
modal_version/_version_generated.py,sha256=
|
169
|
-
modal-0.71.
|
170
|
-
modal-0.71.
|
171
|
-
modal-0.71.
|
172
|
-
modal-0.71.
|
173
|
-
modal-0.71.
|
174
|
-
modal-0.71.
|
168
|
+
modal_version/_version_generated.py,sha256=cnSvdhptI6bv1AtiTbV-_FVYatlo2RYUt2MB2J1rdVs,149
|
169
|
+
modal-0.71.13.dist-info/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
|
170
|
+
modal-0.71.13.dist-info/METADATA,sha256=iN3iHC6_4sMlOR9fHSl0HGvlELImU8UanLI2qt3DMpE,2329
|
171
|
+
modal-0.71.13.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
|
172
|
+
modal-0.71.13.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
|
173
|
+
modal-0.71.13.dist-info/top_level.txt,sha256=1nvYbOSIKcmU50fNrpnQnrrOpj269ei3LzgB6j9xGqg,64
|
174
|
+
modal-0.71.13.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|