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/dict.py
CHANGED
@@ -7,6 +7,7 @@ from synchronicity.async_wrap import asynccontextmanager
|
|
7
7
|
|
8
8
|
from modal_proto import api_pb2
|
9
9
|
|
10
|
+
from ._object import EPHEMERAL_OBJECT_HEARTBEAT_SLEEP, _get_environment_name, _Object, live_method, live_method_gen
|
10
11
|
from ._resolver import Resolver
|
11
12
|
from ._serialization import deserialize, serialize
|
12
13
|
from ._utils.async_utils import TaskContext, synchronize_api
|
@@ -16,7 +17,6 @@ from ._utils.name_utils import check_object_name
|
|
16
17
|
from .client import _Client
|
17
18
|
from .config import logger
|
18
19
|
from .exception import RequestSizeError
|
19
|
-
from .object import EPHEMERAL_OBJECT_HEARTBEAT_SLEEP, _get_environment_name, _Object, live_method, live_method_gen
|
20
20
|
|
21
21
|
|
22
22
|
def _serialize_dict(data):
|
modal/dict.pyi
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
import collections.abc
|
2
|
+
import modal._object
|
2
3
|
import modal.client
|
3
4
|
import modal.object
|
4
5
|
import synchronicity.combined_types
|
@@ -7,7 +8,7 @@ import typing_extensions
|
|
7
8
|
|
8
9
|
def _serialize_dict(data): ...
|
9
10
|
|
10
|
-
class _Dict(modal.
|
11
|
+
class _Dict(modal._object._Object):
|
11
12
|
def __init__(self, data={}): ...
|
12
13
|
@classmethod
|
13
14
|
def ephemeral(
|
@@ -56,6 +57,8 @@ class _Dict(modal.object._Object):
|
|
56
57
|
def values(self) -> collections.abc.AsyncIterator[typing.Any]: ...
|
57
58
|
def items(self) -> collections.abc.AsyncIterator[tuple[typing.Any, typing.Any]]: ...
|
58
59
|
|
60
|
+
SUPERSELF = typing.TypeVar("SUPERSELF", covariant=True)
|
61
|
+
|
59
62
|
class Dict(modal.object.Object):
|
60
63
|
def __init__(self, data={}): ...
|
61
64
|
@classmethod
|
@@ -115,86 +118,86 @@ class Dict(modal.object.Object):
|
|
115
118
|
|
116
119
|
delete: __delete_spec
|
117
120
|
|
118
|
-
class __clear_spec(typing_extensions.Protocol):
|
121
|
+
class __clear_spec(typing_extensions.Protocol[SUPERSELF]):
|
119
122
|
def __call__(self) -> None: ...
|
120
123
|
async def aio(self) -> None: ...
|
121
124
|
|
122
|
-
clear: __clear_spec
|
125
|
+
clear: __clear_spec[typing_extensions.Self]
|
123
126
|
|
124
|
-
class __get_spec(typing_extensions.Protocol):
|
127
|
+
class __get_spec(typing_extensions.Protocol[SUPERSELF]):
|
125
128
|
def __call__(self, key: typing.Any, default: typing.Optional[typing.Any] = None) -> typing.Any: ...
|
126
129
|
async def aio(self, key: typing.Any, default: typing.Optional[typing.Any] = None) -> typing.Any: ...
|
127
130
|
|
128
|
-
get: __get_spec
|
131
|
+
get: __get_spec[typing_extensions.Self]
|
129
132
|
|
130
|
-
class __contains_spec(typing_extensions.Protocol):
|
133
|
+
class __contains_spec(typing_extensions.Protocol[SUPERSELF]):
|
131
134
|
def __call__(self, key: typing.Any) -> bool: ...
|
132
135
|
async def aio(self, key: typing.Any) -> bool: ...
|
133
136
|
|
134
|
-
contains: __contains_spec
|
137
|
+
contains: __contains_spec[typing_extensions.Self]
|
135
138
|
|
136
|
-
class __len_spec(typing_extensions.Protocol):
|
139
|
+
class __len_spec(typing_extensions.Protocol[SUPERSELF]):
|
137
140
|
def __call__(self) -> int: ...
|
138
141
|
async def aio(self) -> int: ...
|
139
142
|
|
140
|
-
len: __len_spec
|
143
|
+
len: __len_spec[typing_extensions.Self]
|
141
144
|
|
142
|
-
class ____getitem___spec(typing_extensions.Protocol):
|
145
|
+
class ____getitem___spec(typing_extensions.Protocol[SUPERSELF]):
|
143
146
|
def __call__(self, key: typing.Any) -> typing.Any: ...
|
144
147
|
async def aio(self, key: typing.Any) -> typing.Any: ...
|
145
148
|
|
146
|
-
__getitem__: ____getitem___spec
|
149
|
+
__getitem__: ____getitem___spec[typing_extensions.Self]
|
147
150
|
|
148
|
-
class __update_spec(typing_extensions.Protocol):
|
151
|
+
class __update_spec(typing_extensions.Protocol[SUPERSELF]):
|
149
152
|
def __call__(self, **kwargs) -> None: ...
|
150
153
|
async def aio(self, **kwargs) -> None: ...
|
151
154
|
|
152
|
-
update: __update_spec
|
155
|
+
update: __update_spec[typing_extensions.Self]
|
153
156
|
|
154
|
-
class __put_spec(typing_extensions.Protocol):
|
157
|
+
class __put_spec(typing_extensions.Protocol[SUPERSELF]):
|
155
158
|
def __call__(self, key: typing.Any, value: typing.Any) -> None: ...
|
156
159
|
async def aio(self, key: typing.Any, value: typing.Any) -> None: ...
|
157
160
|
|
158
|
-
put: __put_spec
|
161
|
+
put: __put_spec[typing_extensions.Self]
|
159
162
|
|
160
|
-
class ____setitem___spec(typing_extensions.Protocol):
|
163
|
+
class ____setitem___spec(typing_extensions.Protocol[SUPERSELF]):
|
161
164
|
def __call__(self, key: typing.Any, value: typing.Any) -> None: ...
|
162
165
|
async def aio(self, key: typing.Any, value: typing.Any) -> None: ...
|
163
166
|
|
164
|
-
__setitem__: ____setitem___spec
|
167
|
+
__setitem__: ____setitem___spec[typing_extensions.Self]
|
165
168
|
|
166
|
-
class __pop_spec(typing_extensions.Protocol):
|
169
|
+
class __pop_spec(typing_extensions.Protocol[SUPERSELF]):
|
167
170
|
def __call__(self, key: typing.Any) -> typing.Any: ...
|
168
171
|
async def aio(self, key: typing.Any) -> typing.Any: ...
|
169
172
|
|
170
|
-
pop: __pop_spec
|
173
|
+
pop: __pop_spec[typing_extensions.Self]
|
171
174
|
|
172
|
-
class ____delitem___spec(typing_extensions.Protocol):
|
175
|
+
class ____delitem___spec(typing_extensions.Protocol[SUPERSELF]):
|
173
176
|
def __call__(self, key: typing.Any) -> typing.Any: ...
|
174
177
|
async def aio(self, key: typing.Any) -> typing.Any: ...
|
175
178
|
|
176
|
-
__delitem__: ____delitem___spec
|
179
|
+
__delitem__: ____delitem___spec[typing_extensions.Self]
|
177
180
|
|
178
|
-
class ____contains___spec(typing_extensions.Protocol):
|
181
|
+
class ____contains___spec(typing_extensions.Protocol[SUPERSELF]):
|
179
182
|
def __call__(self, key: typing.Any) -> bool: ...
|
180
183
|
async def aio(self, key: typing.Any) -> bool: ...
|
181
184
|
|
182
|
-
__contains__: ____contains___spec
|
185
|
+
__contains__: ____contains___spec[typing_extensions.Self]
|
183
186
|
|
184
|
-
class __keys_spec(typing_extensions.Protocol):
|
187
|
+
class __keys_spec(typing_extensions.Protocol[SUPERSELF]):
|
185
188
|
def __call__(self) -> typing.Iterator[typing.Any]: ...
|
186
189
|
def aio(self) -> collections.abc.AsyncIterator[typing.Any]: ...
|
187
190
|
|
188
|
-
keys: __keys_spec
|
191
|
+
keys: __keys_spec[typing_extensions.Self]
|
189
192
|
|
190
|
-
class __values_spec(typing_extensions.Protocol):
|
193
|
+
class __values_spec(typing_extensions.Protocol[SUPERSELF]):
|
191
194
|
def __call__(self) -> typing.Iterator[typing.Any]: ...
|
192
195
|
def aio(self) -> collections.abc.AsyncIterator[typing.Any]: ...
|
193
196
|
|
194
|
-
values: __values_spec
|
197
|
+
values: __values_spec[typing_extensions.Self]
|
195
198
|
|
196
|
-
class __items_spec(typing_extensions.Protocol):
|
199
|
+
class __items_spec(typing_extensions.Protocol[SUPERSELF]):
|
197
200
|
def __call__(self) -> typing.Iterator[tuple[typing.Any, typing.Any]]: ...
|
198
201
|
def aio(self) -> collections.abc.AsyncIterator[tuple[typing.Any, typing.Any]]: ...
|
199
202
|
|
200
|
-
items: __items_spec
|
203
|
+
items: __items_spec[typing_extensions.Self]
|
modal/environments.py
CHANGED
@@ -8,6 +8,7 @@ from google.protobuf.wrappers_pb2 import StringValue
|
|
8
8
|
|
9
9
|
from modal_proto import api_pb2
|
10
10
|
|
11
|
+
from ._object import _Object
|
11
12
|
from ._resolver import Resolver
|
12
13
|
from ._utils.async_utils import synchronize_api, synchronizer
|
13
14
|
from ._utils.deprecation import renamed_parameter
|
@@ -15,7 +16,6 @@ from ._utils.grpc_utils import retry_transient_errors
|
|
15
16
|
from ._utils.name_utils import check_object_name
|
16
17
|
from .client import _Client
|
17
18
|
from .config import config, logger
|
18
|
-
from .object import _Object
|
19
19
|
|
20
20
|
|
21
21
|
@dataclass(frozen=True)
|
modal/environments.pyi
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
import google.protobuf.message
|
2
|
+
import modal._object
|
2
3
|
import modal.client
|
3
4
|
import modal.object
|
4
5
|
import modal_proto.api_pb2
|
@@ -16,7 +17,7 @@ class EnvironmentSettings:
|
|
16
17
|
def __delattr__(self, name): ...
|
17
18
|
def __hash__(self): ...
|
18
19
|
|
19
|
-
class _Environment(modal.
|
20
|
+
class _Environment(modal._object._Object):
|
20
21
|
_settings: EnvironmentSettings
|
21
22
|
|
22
23
|
def __init__(self): ...
|
modal/experimental.py
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
# Copyright Modal Labs 2022
|
2
|
-
from
|
3
|
-
|
4
|
-
Callable,
|
5
|
-
)
|
2
|
+
from dataclasses import dataclass
|
3
|
+
from typing import Any, Callable, Optional
|
6
4
|
|
7
|
-
import
|
8
|
-
from modal.functions import _Function
|
5
|
+
from modal_proto import api_pb2
|
9
6
|
|
7
|
+
from ._clustered_functions import ClusterInfo, get_cluster_info as _get_cluster_info
|
8
|
+
from ._object import _get_environment_name
|
10
9
|
from ._runtime.container_io_manager import _ContainerIOManager
|
11
|
-
from .
|
12
|
-
|
13
|
-
|
10
|
+
from ._utils.async_utils import synchronizer
|
11
|
+
from .client import _Client
|
12
|
+
from .exception import InvalidError
|
13
|
+
from .functions import _Function
|
14
14
|
from .partial_function import _PartialFunction, _PartialFunctionFlags
|
15
15
|
|
16
16
|
|
@@ -65,5 +65,41 @@ def clustered(size: int, broadcast: bool = True):
|
|
65
65
|
return wrapper
|
66
66
|
|
67
67
|
|
68
|
-
def get_cluster_info() ->
|
69
|
-
return
|
68
|
+
def get_cluster_info() -> ClusterInfo:
|
69
|
+
return _get_cluster_info()
|
70
|
+
|
71
|
+
|
72
|
+
@dataclass
|
73
|
+
class AppInfo:
|
74
|
+
app_id: str
|
75
|
+
name: str
|
76
|
+
containers: int
|
77
|
+
|
78
|
+
|
79
|
+
@synchronizer.create_blocking
|
80
|
+
async def list_deployed_apps(environment_name: str = "", client: Optional[_Client] = None) -> list[AppInfo]:
|
81
|
+
"""List deployed Apps along with the number of containers currently running."""
|
82
|
+
# This function exists to provide backwards compatibility for some users who had been
|
83
|
+
# calling into the private function that previously backed the `modal app list` CLI command.
|
84
|
+
# We plan to add more Python API for exposing this sort of information, but we haven't
|
85
|
+
# settled on a design we're happy with yet. In the meantime, this function will continue
|
86
|
+
# to support existing codebases. It's likely that the final API will be different
|
87
|
+
# (e.g. more oriented around the App object). This function should be gracefully deprecated
|
88
|
+
# one the new API is released.
|
89
|
+
client = client or await _Client.from_env()
|
90
|
+
|
91
|
+
resp: api_pb2.AppListResponse = await client.stub.AppList(
|
92
|
+
api_pb2.AppListRequest(environment_name=_get_environment_name(environment_name))
|
93
|
+
)
|
94
|
+
|
95
|
+
app_infos = []
|
96
|
+
for app_stats in resp.apps:
|
97
|
+
if app_stats.state == api_pb2.APP_STATE_DEPLOYED:
|
98
|
+
app_infos.append(
|
99
|
+
AppInfo(
|
100
|
+
app_id=app_stats.app_id,
|
101
|
+
name=app_stats.description,
|
102
|
+
containers=app_stats.n_running_tasks,
|
103
|
+
)
|
104
|
+
)
|
105
|
+
return app_infos
|
modal/experimental.pyi
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
import modal._clustered_functions
|
2
|
+
import modal.client
|
3
|
+
import typing
|
4
|
+
import typing_extensions
|
5
|
+
|
6
|
+
def stop_fetching_inputs(): ...
|
7
|
+
def get_local_input_concurrency(): ...
|
8
|
+
def set_local_input_concurrency(concurrency: int): ...
|
9
|
+
def clustered(size: int, broadcast: bool = True): ...
|
10
|
+
def get_cluster_info() -> modal._clustered_functions.ClusterInfo: ...
|
11
|
+
|
12
|
+
class AppInfo:
|
13
|
+
app_id: str
|
14
|
+
name: str
|
15
|
+
containers: int
|
16
|
+
|
17
|
+
def __init__(self, app_id: str, name: str, containers: int) -> None: ...
|
18
|
+
def __repr__(self): ...
|
19
|
+
def __eq__(self, other): ...
|
20
|
+
|
21
|
+
class __list_deployed_apps_spec(typing_extensions.Protocol):
|
22
|
+
def __call__(
|
23
|
+
self, environment_name: str = "", client: typing.Optional[modal.client.Client] = None
|
24
|
+
) -> list[AppInfo]: ...
|
25
|
+
async def aio(
|
26
|
+
self, environment_name: str = "", client: typing.Optional[modal.client.Client] = None
|
27
|
+
) -> list[AppInfo]: ...
|
28
|
+
|
29
|
+
list_deployed_apps: __list_deployed_apps_spec
|
modal/file_io.pyi
CHANGED
@@ -100,6 +100,8 @@ class __replace_bytes_spec(typing_extensions.Protocol):
|
|
100
100
|
|
101
101
|
replace_bytes: __replace_bytes_spec
|
102
102
|
|
103
|
+
SUPERSELF = typing.TypeVar("SUPERSELF", covariant=True)
|
104
|
+
|
103
105
|
T_INNER = typing.TypeVar("T_INNER", covariant=True)
|
104
106
|
|
105
107
|
class FileIO(typing.Generic[T]):
|
@@ -112,37 +114,37 @@ class FileIO(typing.Generic[T]):
|
|
112
114
|
def _validate_mode(self, mode: str) -> None: ...
|
113
115
|
def _handle_error(self, error: modal_proto.api_pb2.SystemErrorMessage) -> None: ...
|
114
116
|
|
115
|
-
class ___consume_output_spec(typing_extensions.Protocol):
|
117
|
+
class ___consume_output_spec(typing_extensions.Protocol[SUPERSELF]):
|
116
118
|
def __call__(self, exec_id: str) -> typing.Iterator[typing.Optional[bytes]]: ...
|
117
119
|
def aio(self, exec_id: str) -> typing.AsyncIterator[typing.Optional[bytes]]: ...
|
118
120
|
|
119
|
-
_consume_output: ___consume_output_spec
|
121
|
+
_consume_output: ___consume_output_spec[typing_extensions.Self]
|
120
122
|
|
121
|
-
class ___consume_watch_output_spec(typing_extensions.Protocol):
|
123
|
+
class ___consume_watch_output_spec(typing_extensions.Protocol[SUPERSELF]):
|
122
124
|
def __call__(self, exec_id: str) -> None: ...
|
123
125
|
async def aio(self, exec_id: str) -> None: ...
|
124
126
|
|
125
|
-
_consume_watch_output: ___consume_watch_output_spec
|
127
|
+
_consume_watch_output: ___consume_watch_output_spec[typing_extensions.Self]
|
126
128
|
|
127
|
-
class ___parse_watch_output_spec(typing_extensions.Protocol):
|
129
|
+
class ___parse_watch_output_spec(typing_extensions.Protocol[SUPERSELF]):
|
128
130
|
def __call__(self, event: bytes) -> typing.Optional[FileWatchEvent]: ...
|
129
131
|
async def aio(self, event: bytes) -> typing.Optional[FileWatchEvent]: ...
|
130
132
|
|
131
|
-
_parse_watch_output: ___parse_watch_output_spec
|
133
|
+
_parse_watch_output: ___parse_watch_output_spec[typing_extensions.Self]
|
132
134
|
|
133
|
-
class ___wait_spec(typing_extensions.Protocol):
|
135
|
+
class ___wait_spec(typing_extensions.Protocol[SUPERSELF]):
|
134
136
|
def __call__(self, exec_id: str) -> bytes: ...
|
135
137
|
async def aio(self, exec_id: str) -> bytes: ...
|
136
138
|
|
137
|
-
_wait: ___wait_spec
|
139
|
+
_wait: ___wait_spec[typing_extensions.Self]
|
138
140
|
|
139
141
|
def _validate_type(self, data: typing.Union[bytes, str]) -> None: ...
|
140
142
|
|
141
|
-
class ___open_file_spec(typing_extensions.Protocol):
|
143
|
+
class ___open_file_spec(typing_extensions.Protocol[SUPERSELF]):
|
142
144
|
def __call__(self, path: str, mode: str) -> None: ...
|
143
145
|
async def aio(self, path: str, mode: str) -> None: ...
|
144
146
|
|
145
|
-
_open_file: ___open_file_spec
|
147
|
+
_open_file: ___open_file_spec[typing_extensions.Self]
|
146
148
|
|
147
149
|
@classmethod
|
148
150
|
def create(
|
@@ -153,49 +155,49 @@ class FileIO(typing.Generic[T]):
|
|
153
155
|
task_id: str,
|
154
156
|
) -> FileIO: ...
|
155
157
|
|
156
|
-
class ___make_read_request_spec(typing_extensions.Protocol):
|
158
|
+
class ___make_read_request_spec(typing_extensions.Protocol[SUPERSELF]):
|
157
159
|
def __call__(self, n: typing.Optional[int]) -> bytes: ...
|
158
160
|
async def aio(self, n: typing.Optional[int]) -> bytes: ...
|
159
161
|
|
160
|
-
_make_read_request: ___make_read_request_spec
|
162
|
+
_make_read_request: ___make_read_request_spec[typing_extensions.Self]
|
161
163
|
|
162
|
-
class __read_spec(typing_extensions.Protocol[T_INNER]):
|
164
|
+
class __read_spec(typing_extensions.Protocol[T_INNER, SUPERSELF]):
|
163
165
|
def __call__(self, n: typing.Optional[int] = None) -> T_INNER: ...
|
164
166
|
async def aio(self, n: typing.Optional[int] = None) -> T_INNER: ...
|
165
167
|
|
166
|
-
read: __read_spec[T]
|
168
|
+
read: __read_spec[T, typing_extensions.Self]
|
167
169
|
|
168
|
-
class __readline_spec(typing_extensions.Protocol[T_INNER]):
|
170
|
+
class __readline_spec(typing_extensions.Protocol[T_INNER, SUPERSELF]):
|
169
171
|
def __call__(self) -> T_INNER: ...
|
170
172
|
async def aio(self) -> T_INNER: ...
|
171
173
|
|
172
|
-
readline: __readline_spec[T]
|
174
|
+
readline: __readline_spec[T, typing_extensions.Self]
|
173
175
|
|
174
|
-
class __readlines_spec(typing_extensions.Protocol[T_INNER]):
|
176
|
+
class __readlines_spec(typing_extensions.Protocol[T_INNER, SUPERSELF]):
|
175
177
|
def __call__(self) -> typing.Sequence[T_INNER]: ...
|
176
178
|
async def aio(self) -> typing.Sequence[T_INNER]: ...
|
177
179
|
|
178
|
-
readlines: __readlines_spec[T]
|
180
|
+
readlines: __readlines_spec[T, typing_extensions.Self]
|
179
181
|
|
180
|
-
class __write_spec(typing_extensions.Protocol):
|
182
|
+
class __write_spec(typing_extensions.Protocol[SUPERSELF]):
|
181
183
|
def __call__(self, data: typing.Union[bytes, str]) -> None: ...
|
182
184
|
async def aio(self, data: typing.Union[bytes, str]) -> None: ...
|
183
185
|
|
184
|
-
write: __write_spec
|
186
|
+
write: __write_spec[typing_extensions.Self]
|
185
187
|
|
186
|
-
class __flush_spec(typing_extensions.Protocol):
|
188
|
+
class __flush_spec(typing_extensions.Protocol[SUPERSELF]):
|
187
189
|
def __call__(self) -> None: ...
|
188
190
|
async def aio(self) -> None: ...
|
189
191
|
|
190
|
-
flush: __flush_spec
|
192
|
+
flush: __flush_spec[typing_extensions.Self]
|
191
193
|
|
192
194
|
def _get_whence(self, whence: int): ...
|
193
195
|
|
194
|
-
class __seek_spec(typing_extensions.Protocol):
|
196
|
+
class __seek_spec(typing_extensions.Protocol[SUPERSELF]):
|
195
197
|
def __call__(self, offset: int, whence: int = 0) -> None: ...
|
196
198
|
async def aio(self, offset: int, whence: int = 0) -> None: ...
|
197
199
|
|
198
|
-
seek: __seek_spec
|
200
|
+
seek: __seek_spec[typing_extensions.Self]
|
199
201
|
|
200
202
|
@classmethod
|
201
203
|
def ls(cls, path: str, client: modal.client.Client, task_id: str) -> list[str]: ...
|
@@ -214,17 +216,17 @@ class FileIO(typing.Generic[T]):
|
|
214
216
|
timeout: typing.Optional[int] = None,
|
215
217
|
) -> typing.Iterator[FileWatchEvent]: ...
|
216
218
|
|
217
|
-
class ___close_spec(typing_extensions.Protocol):
|
219
|
+
class ___close_spec(typing_extensions.Protocol[SUPERSELF]):
|
218
220
|
def __call__(self) -> None: ...
|
219
221
|
async def aio(self) -> None: ...
|
220
222
|
|
221
|
-
_close: ___close_spec
|
223
|
+
_close: ___close_spec[typing_extensions.Self]
|
222
224
|
|
223
|
-
class __close_spec(typing_extensions.Protocol):
|
225
|
+
class __close_spec(typing_extensions.Protocol[SUPERSELF]):
|
224
226
|
def __call__(self) -> None: ...
|
225
227
|
async def aio(self) -> None: ...
|
226
228
|
|
227
|
-
close: __close_spec
|
229
|
+
close: __close_spec[typing_extensions.Self]
|
228
230
|
|
229
231
|
def _check_writable(self) -> None: ...
|
230
232
|
def _check_readable(self) -> None: ...
|
modal/file_pattern_matcher.py
CHANGED
@@ -35,7 +35,7 @@ class _AbstractPatternMatcher:
|
|
35
35
|
"""
|
36
36
|
return _CustomPatternMatcher(lambda path: not self(path))
|
37
37
|
|
38
|
-
def
|
38
|
+
def _with_repr(self, custom_repr) -> "_AbstractPatternMatcher":
|
39
39
|
# use to give an instance of a matcher a custom name - useful for visualizing default values in signatures
|
40
40
|
self._custom_repr = custom_repr
|
41
41
|
return self
|
@@ -60,7 +60,24 @@ class _CustomPatternMatcher(_AbstractPatternMatcher):
|
|
60
60
|
|
61
61
|
|
62
62
|
class FilePatternMatcher(_AbstractPatternMatcher):
|
63
|
-
"""
|
63
|
+
"""
|
64
|
+
Allows matching file Path objects against a list of patterns.
|
65
|
+
|
66
|
+
**Usage:**
|
67
|
+
```python
|
68
|
+
from pathlib import Path
|
69
|
+
from modal import FilePatternMatcher
|
70
|
+
|
71
|
+
matcher = FilePatternMatcher("*.py")
|
72
|
+
|
73
|
+
assert matcher(Path("foo.py"))
|
74
|
+
|
75
|
+
# You can also negate the matcher.
|
76
|
+
negated_matcher = ~matcher
|
77
|
+
|
78
|
+
assert not negated_matcher(Path("foo.py"))
|
79
|
+
```
|
80
|
+
"""
|
64
81
|
|
65
82
|
patterns: list[Pattern]
|
66
83
|
_delayed_init: Callable[[], None] = None
|
@@ -95,18 +112,26 @@ class FilePatternMatcher(_AbstractPatternMatcher):
|
|
95
112
|
self._set_patterns(pattern)
|
96
113
|
|
97
114
|
@classmethod
|
98
|
-
def from_file(cls, file_path: Path) -> "FilePatternMatcher":
|
115
|
+
def from_file(cls, file_path: Union[str, Path]) -> "FilePatternMatcher":
|
99
116
|
"""Initialize a new FilePatternMatcher instance from a file.
|
100
117
|
|
101
118
|
The patterns in the file will be read lazily when the matcher is first used.
|
102
119
|
|
103
120
|
Args:
|
104
121
|
file_path (Path): The path to the file containing patterns.
|
122
|
+
|
123
|
+
**Usage:**
|
124
|
+
```python
|
125
|
+
from modal import FilePatternMatcher
|
126
|
+
|
127
|
+
matcher = FilePatternMatcher.from_file("/path/to/ignorefile")
|
128
|
+
```
|
129
|
+
|
105
130
|
"""
|
106
131
|
uninitialized = cls.__new__(cls)
|
107
132
|
|
108
133
|
def _delayed_init():
|
109
|
-
uninitialized._set_patterns(file_path.read_text("utf8").splitlines())
|
134
|
+
uninitialized._set_patterns(Path(file_path).read_text("utf8").splitlines())
|
110
135
|
uninitialized._delayed_init = None
|
111
136
|
|
112
137
|
uninitialized._delayed_init = _delayed_init
|
@@ -151,33 +176,15 @@ class FilePatternMatcher(_AbstractPatternMatcher):
|
|
151
176
|
return matched
|
152
177
|
|
153
178
|
def __call__(self, file_path: Path) -> bool:
|
154
|
-
"""Check if the path matches any of the patterns.
|
155
|
-
|
156
|
-
Args:
|
157
|
-
file_path (Path): The path to check.
|
158
|
-
|
159
|
-
Returns:
|
160
|
-
True if the path matches any of the patterns.
|
161
|
-
|
162
|
-
Usage:
|
163
|
-
```python
|
164
|
-
from pathlib import Path
|
165
|
-
from modal import FilePatternMatcher
|
166
|
-
|
167
|
-
matcher = FilePatternMatcher("*.py")
|
168
|
-
|
169
|
-
assert matcher(Path("foo.py"))
|
170
|
-
```
|
171
|
-
"""
|
172
179
|
if self._delayed_init:
|
173
180
|
self._delayed_init()
|
174
181
|
return self._matches(str(file_path))
|
175
182
|
|
176
183
|
|
177
|
-
#
|
184
|
+
# _with_repr allows us to use this matcher as a default value in a function signature
|
178
185
|
# and get a nice repr in the docs and auto-generated type stubs:
|
179
|
-
NON_PYTHON_FILES = (~FilePatternMatcher("**/*.py")).
|
180
|
-
_NOTHING = (~FilePatternMatcher()).
|
186
|
+
NON_PYTHON_FILES = (~FilePatternMatcher("**/*.py"))._with_repr(f"{__name__}.NON_PYTHON_FILES")
|
187
|
+
_NOTHING = (~FilePatternMatcher())._with_repr(f"{__name__}._NOTHING") # match everything = ignore nothing
|
181
188
|
|
182
189
|
|
183
190
|
def _ignore_fn(ignore: Union[Sequence[str], Callable[[Path], bool]]) -> Callable[[Path], bool]:
|