modal 0.62.16__py3-none-any.whl → 0.72.11__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/__init__.py +17 -13
- modal/__main__.py +41 -3
- modal/_clustered_functions.py +80 -0
- modal/_clustered_functions.pyi +22 -0
- modal/_container_entrypoint.py +420 -937
- modal/_ipython.py +3 -13
- modal/_location.py +17 -10
- modal/_output.py +243 -99
- modal/_pty.py +2 -2
- modal/_resolver.py +55 -59
- modal/_resources.py +51 -0
- modal/_runtime/__init__.py +1 -0
- modal/_runtime/asgi.py +519 -0
- modal/_runtime/container_io_manager.py +1036 -0
- modal/_runtime/execution_context.py +89 -0
- modal/_runtime/telemetry.py +169 -0
- modal/_runtime/user_code_imports.py +356 -0
- modal/_serialization.py +134 -9
- modal/_traceback.py +47 -187
- modal/_tunnel.py +52 -16
- modal/_tunnel.pyi +19 -36
- modal/_utils/app_utils.py +3 -17
- modal/_utils/async_utils.py +479 -100
- modal/_utils/blob_utils.py +157 -186
- modal/_utils/bytes_io_segment_payload.py +97 -0
- modal/_utils/deprecation.py +89 -0
- modal/_utils/docker_utils.py +98 -0
- modal/_utils/function_utils.py +460 -171
- modal/_utils/grpc_testing.py +47 -31
- modal/_utils/grpc_utils.py +62 -109
- modal/_utils/hash_utils.py +61 -19
- modal/_utils/http_utils.py +39 -9
- modal/_utils/logger.py +2 -1
- modal/_utils/mount_utils.py +34 -16
- modal/_utils/name_utils.py +58 -0
- modal/_utils/package_utils.py +14 -1
- modal/_utils/pattern_utils.py +205 -0
- modal/_utils/rand_pb_testing.py +5 -7
- modal/_utils/shell_utils.py +15 -49
- modal/_vendor/a2wsgi_wsgi.py +62 -72
- modal/_vendor/cloudpickle.py +1 -1
- modal/_watcher.py +14 -12
- modal/app.py +1003 -314
- modal/app.pyi +540 -264
- modal/call_graph.py +7 -6
- modal/cli/_download.py +63 -53
- modal/cli/_traceback.py +200 -0
- modal/cli/app.py +205 -45
- modal/cli/config.py +12 -5
- modal/cli/container.py +62 -14
- modal/cli/dict.py +128 -0
- modal/cli/entry_point.py +26 -13
- modal/cli/environment.py +40 -9
- modal/cli/import_refs.py +64 -58
- modal/cli/launch.py +32 -18
- modal/cli/network_file_system.py +64 -83
- modal/cli/profile.py +1 -1
- modal/cli/programs/run_jupyter.py +35 -10
- modal/cli/programs/vscode.py +60 -10
- modal/cli/queues.py +131 -0
- modal/cli/run.py +234 -131
- modal/cli/secret.py +8 -7
- modal/cli/token.py +7 -2
- modal/cli/utils.py +79 -10
- modal/cli/volume.py +110 -109
- modal/client.py +250 -144
- modal/client.pyi +157 -118
- modal/cloud_bucket_mount.py +108 -34
- modal/cloud_bucket_mount.pyi +32 -38
- modal/cls.py +535 -148
- modal/cls.pyi +190 -146
- modal/config.py +41 -19
- modal/container_process.py +177 -0
- modal/container_process.pyi +82 -0
- modal/dict.py +111 -65
- modal/dict.pyi +136 -131
- modal/environments.py +106 -5
- modal/environments.pyi +77 -25
- modal/exception.py +34 -43
- modal/experimental.py +61 -2
- modal/extensions/ipython.py +5 -5
- modal/file_io.py +537 -0
- modal/file_io.pyi +235 -0
- modal/file_pattern_matcher.py +197 -0
- modal/functions.py +906 -911
- modal/functions.pyi +466 -430
- modal/gpu.py +57 -44
- modal/image.py +1089 -479
- modal/image.pyi +584 -228
- modal/io_streams.py +434 -0
- modal/io_streams.pyi +122 -0
- modal/mount.py +314 -101
- modal/mount.pyi +241 -235
- modal/network_file_system.py +92 -92
- modal/network_file_system.pyi +152 -110
- modal/object.py +67 -36
- modal/object.pyi +166 -143
- modal/output.py +63 -0
- modal/parallel_map.py +434 -0
- modal/parallel_map.pyi +75 -0
- modal/partial_function.py +282 -117
- modal/partial_function.pyi +222 -129
- modal/proxy.py +15 -12
- modal/proxy.pyi +3 -8
- modal/queue.py +182 -65
- modal/queue.pyi +218 -118
- modal/requirements/2024.04.txt +29 -0
- modal/requirements/2024.10.txt +16 -0
- modal/requirements/README.md +21 -0
- modal/requirements/base-images.json +22 -0
- modal/retries.py +48 -7
- modal/runner.py +459 -156
- modal/runner.pyi +135 -71
- modal/running_app.py +38 -0
- modal/sandbox.py +514 -236
- modal/sandbox.pyi +397 -169
- modal/schedule.py +4 -4
- modal/scheduler_placement.py +20 -3
- modal/secret.py +56 -31
- modal/secret.pyi +62 -42
- modal/serving.py +51 -56
- modal/serving.pyi +44 -36
- modal/stream_type.py +15 -0
- modal/token_flow.py +5 -3
- modal/token_flow.pyi +37 -32
- modal/volume.py +285 -157
- modal/volume.pyi +249 -184
- {modal-0.62.16.dist-info → modal-0.72.11.dist-info}/METADATA +7 -7
- modal-0.72.11.dist-info/RECORD +174 -0
- {modal-0.62.16.dist-info → modal-0.72.11.dist-info}/top_level.txt +0 -1
- modal_docs/gen_reference_docs.py +3 -1
- modal_docs/mdmd/mdmd.py +0 -1
- modal_docs/mdmd/signatures.py +5 -2
- modal_global_objects/images/base_images.py +28 -0
- modal_global_objects/mounts/python_standalone.py +2 -2
- modal_proto/__init__.py +1 -1
- modal_proto/api.proto +1288 -533
- modal_proto/api_grpc.py +856 -456
- modal_proto/api_pb2.py +2165 -1157
- modal_proto/api_pb2.pyi +8859 -0
- modal_proto/api_pb2_grpc.py +1674 -855
- modal_proto/api_pb2_grpc.pyi +1416 -0
- modal_proto/modal_api_grpc.py +149 -0
- modal_proto/modal_options_grpc.py +3 -0
- modal_proto/options_pb2.pyi +20 -0
- modal_proto/options_pb2_grpc.pyi +7 -0
- modal_proto/py.typed +0 -0
- modal_version/__init__.py +1 -1
- modal_version/_version_generated.py +2 -2
- modal/_asgi.py +0 -370
- modal/_container_entrypoint.pyi +0 -378
- modal/_container_exec.py +0 -128
- modal/_sandbox_shell.py +0 -49
- modal/shared_volume.py +0 -23
- modal/shared_volume.pyi +0 -24
- modal/stub.py +0 -783
- modal/stub.pyi +0 -332
- modal-0.62.16.dist-info/RECORD +0 -198
- modal_global_objects/images/conda.py +0 -15
- modal_global_objects/images/debian_slim.py +0 -15
- modal_global_objects/images/micromamba.py +0 -15
- test/__init__.py +0 -1
- test/aio_test.py +0 -12
- test/async_utils_test.py +0 -262
- test/blob_test.py +0 -67
- test/cli_imports_test.py +0 -149
- test/cli_test.py +0 -659
- test/client_test.py +0 -194
- test/cls_test.py +0 -630
- test/config_test.py +0 -137
- test/conftest.py +0 -1420
- test/container_app_test.py +0 -32
- test/container_test.py +0 -1389
- test/cpu_test.py +0 -23
- test/decorator_test.py +0 -85
- test/deprecation_test.py +0 -34
- test/dict_test.py +0 -33
- test/e2e_test.py +0 -68
- test/error_test.py +0 -7
- test/function_serialization_test.py +0 -32
- test/function_test.py +0 -653
- test/function_utils_test.py +0 -101
- test/gpu_test.py +0 -159
- test/grpc_utils_test.py +0 -141
- test/helpers.py +0 -42
- test/image_test.py +0 -669
- test/live_reload_test.py +0 -80
- test/lookup_test.py +0 -70
- test/mdmd_test.py +0 -329
- test/mount_test.py +0 -162
- test/mounted_files_test.py +0 -329
- test/network_file_system_test.py +0 -181
- test/notebook_test.py +0 -66
- test/object_test.py +0 -41
- test/package_utils_test.py +0 -25
- test/queue_test.py +0 -97
- test/resolver_test.py +0 -58
- test/retries_test.py +0 -67
- test/runner_test.py +0 -85
- test/sandbox_test.py +0 -191
- test/schedule_test.py +0 -15
- test/scheduler_placement_test.py +0 -29
- test/secret_test.py +0 -78
- test/serialization_test.py +0 -42
- test/stub_composition_test.py +0 -10
- test/stub_test.py +0 -360
- test/test_asgi_wrapper.py +0 -234
- test/token_flow_test.py +0 -18
- test/traceback_test.py +0 -135
- test/tunnel_test.py +0 -29
- test/utils_test.py +0 -88
- test/version_test.py +0 -14
- test/volume_test.py +0 -341
- test/watcher_test.py +0 -30
- test/webhook_test.py +0 -146
- /modal/{requirements.312.txt → requirements/2023.12.312.txt} +0 -0
- /modal/{requirements.txt → requirements/2023.12.txt} +0 -0
- {modal-0.62.16.dist-info → modal-0.72.11.dist-info}/LICENSE +0 -0
- {modal-0.62.16.dist-info → modal-0.72.11.dist-info}/WHEEL +0 -0
- {modal-0.62.16.dist-info → modal-0.72.11.dist-info}/entry_points.txt +0 -0
modal/_container_entrypoint.pyi
DELETED
@@ -1,378 +0,0 @@
|
|
1
|
-
import asyncio.queues
|
2
|
-
import collections.abc
|
3
|
-
import modal.app
|
4
|
-
import modal.client
|
5
|
-
import modal.functions
|
6
|
-
import modal.stub
|
7
|
-
import modal_proto.api_pb2
|
8
|
-
import typing
|
9
|
-
import typing_extensions
|
10
|
-
|
11
|
-
class UserException(Exception):
|
12
|
-
...
|
13
|
-
|
14
|
-
class UserCodeEventLoop:
|
15
|
-
def __enter__(self):
|
16
|
-
...
|
17
|
-
|
18
|
-
def __exit__(self, exc_type, exc_value, traceback):
|
19
|
-
...
|
20
|
-
|
21
|
-
def run(self, coro):
|
22
|
-
...
|
23
|
-
|
24
|
-
|
25
|
-
class _FunctionIOManager:
|
26
|
-
def __init__(self, container_args: modal_proto.api_pb2.ContainerArguments, client: modal.client._Client):
|
27
|
-
...
|
28
|
-
|
29
|
-
async def initialize_app(self) -> modal.app._ContainerApp:
|
30
|
-
...
|
31
|
-
|
32
|
-
async def _run_heartbeat_loop(self):
|
33
|
-
...
|
34
|
-
|
35
|
-
async def _heartbeat_handle_cancellations(self) -> bool:
|
36
|
-
...
|
37
|
-
|
38
|
-
def heartbeats(self):
|
39
|
-
...
|
40
|
-
|
41
|
-
def stop_heartbeat(self):
|
42
|
-
...
|
43
|
-
|
44
|
-
async def get_serialized_function(self) -> typing.Tuple[typing.Union[typing.Any, None], typing.Callable]:
|
45
|
-
...
|
46
|
-
|
47
|
-
def serialize(self, obj: typing.Any) -> bytes:
|
48
|
-
...
|
49
|
-
|
50
|
-
def deserialize(self, data: bytes) -> typing.Any:
|
51
|
-
...
|
52
|
-
|
53
|
-
def serialize_data_format(self, obj: typing.Any, data_format: int) -> bytes:
|
54
|
-
...
|
55
|
-
|
56
|
-
def deserialize_data_format(self, data: bytes, data_format: int) -> typing.Any:
|
57
|
-
...
|
58
|
-
|
59
|
-
def get_data_in(self, function_call_id: str) -> typing.AsyncIterator[typing.Any]:
|
60
|
-
...
|
61
|
-
|
62
|
-
async def put_data_out(self, function_call_id: str, start_index: int, data_format: int, messages_bytes: typing.List[typing.Any]) -> None:
|
63
|
-
...
|
64
|
-
|
65
|
-
async def generator_output_task(self, function_call_id: str, data_format: int, message_rx: asyncio.queues.Queue) -> None:
|
66
|
-
...
|
67
|
-
|
68
|
-
async def _queue_create(self, size: int) -> asyncio.queues.Queue:
|
69
|
-
...
|
70
|
-
|
71
|
-
async def _queue_put(self, queue: asyncio.queues.Queue, value: typing.Any) -> None:
|
72
|
-
...
|
73
|
-
|
74
|
-
async def populate_input_blobs(self, item: modal_proto.api_pb2.FunctionInput):
|
75
|
-
...
|
76
|
-
|
77
|
-
def get_average_call_time(self) -> float:
|
78
|
-
...
|
79
|
-
|
80
|
-
def get_max_inputs_to_fetch(self):
|
81
|
-
...
|
82
|
-
|
83
|
-
def _generate_inputs(self) -> typing.AsyncIterator[typing.Tuple[str, str, modal_proto.api_pb2.FunctionInput]]:
|
84
|
-
...
|
85
|
-
|
86
|
-
def run_inputs_outputs(self, input_concurrency: int = 1) -> typing.AsyncIterator[typing.Tuple[str, str, typing.Any, typing.Any]]:
|
87
|
-
...
|
88
|
-
|
89
|
-
async def _push_output(self, input_id, started_at: float, data_format=0, **kwargs):
|
90
|
-
...
|
91
|
-
|
92
|
-
def serialize_exception(self, exc: BaseException) -> typing.Union[bytes, None]:
|
93
|
-
...
|
94
|
-
|
95
|
-
def serialize_traceback(self, exc: BaseException) -> typing.Tuple[typing.Union[bytes, None], typing.Union[bytes, None]]:
|
96
|
-
...
|
97
|
-
|
98
|
-
def handle_user_exception(self) -> typing.AsyncGenerator[None, None]:
|
99
|
-
...
|
100
|
-
|
101
|
-
def handle_input_exception(self, input_id, started_at: float) -> typing.AsyncGenerator[None, None]:
|
102
|
-
...
|
103
|
-
|
104
|
-
async def complete_call(self, started_at):
|
105
|
-
...
|
106
|
-
|
107
|
-
async def push_output(self, input_id, started_at: float, data: typing.Any, data_format: int) -> None:
|
108
|
-
...
|
109
|
-
|
110
|
-
async def restore(self) -> None:
|
111
|
-
...
|
112
|
-
|
113
|
-
async def checkpoint(self) -> None:
|
114
|
-
...
|
115
|
-
|
116
|
-
async def volume_commit(self, volume_ids: typing.List[str]) -> None:
|
117
|
-
...
|
118
|
-
|
119
|
-
|
120
|
-
class FunctionIOManager:
|
121
|
-
def __init__(self, container_args: modal_proto.api_pb2.ContainerArguments, client: modal.client.Client):
|
122
|
-
...
|
123
|
-
|
124
|
-
class __initialize_app_spec(typing_extensions.Protocol):
|
125
|
-
def __call__(self) -> modal.app.ContainerApp:
|
126
|
-
...
|
127
|
-
|
128
|
-
async def aio(self, *args, **kwargs) -> modal.app.ContainerApp:
|
129
|
-
...
|
130
|
-
|
131
|
-
initialize_app: __initialize_app_spec
|
132
|
-
|
133
|
-
class ___run_heartbeat_loop_spec(typing_extensions.Protocol):
|
134
|
-
def __call__(self):
|
135
|
-
...
|
136
|
-
|
137
|
-
async def aio(self, *args, **kwargs):
|
138
|
-
...
|
139
|
-
|
140
|
-
_run_heartbeat_loop: ___run_heartbeat_loop_spec
|
141
|
-
|
142
|
-
class ___heartbeat_handle_cancellations_spec(typing_extensions.Protocol):
|
143
|
-
def __call__(self) -> bool:
|
144
|
-
...
|
145
|
-
|
146
|
-
async def aio(self, *args, **kwargs) -> bool:
|
147
|
-
...
|
148
|
-
|
149
|
-
_heartbeat_handle_cancellations: ___heartbeat_handle_cancellations_spec
|
150
|
-
|
151
|
-
def heartbeats(self):
|
152
|
-
...
|
153
|
-
|
154
|
-
def stop_heartbeat(self):
|
155
|
-
...
|
156
|
-
|
157
|
-
class __get_serialized_function_spec(typing_extensions.Protocol):
|
158
|
-
def __call__(self) -> typing.Tuple[typing.Union[typing.Any, None], typing.Callable]:
|
159
|
-
...
|
160
|
-
|
161
|
-
async def aio(self, *args, **kwargs) -> typing.Tuple[typing.Union[typing.Any, None], typing.Callable]:
|
162
|
-
...
|
163
|
-
|
164
|
-
get_serialized_function: __get_serialized_function_spec
|
165
|
-
|
166
|
-
def serialize(self, obj: typing.Any) -> bytes:
|
167
|
-
...
|
168
|
-
|
169
|
-
def deserialize(self, data: bytes) -> typing.Any:
|
170
|
-
...
|
171
|
-
|
172
|
-
def serialize_data_format(self, obj: typing.Any, data_format: int) -> bytes:
|
173
|
-
...
|
174
|
-
|
175
|
-
def deserialize_data_format(self, data: bytes, data_format: int) -> typing.Any:
|
176
|
-
...
|
177
|
-
|
178
|
-
class __get_data_in_spec(typing_extensions.Protocol):
|
179
|
-
def __call__(self, function_call_id: str) -> typing.Iterator[typing.Any]:
|
180
|
-
...
|
181
|
-
|
182
|
-
def aio(self, function_call_id: str) -> typing.AsyncIterator[typing.Any]:
|
183
|
-
...
|
184
|
-
|
185
|
-
get_data_in: __get_data_in_spec
|
186
|
-
|
187
|
-
class __put_data_out_spec(typing_extensions.Protocol):
|
188
|
-
def __call__(self, function_call_id: str, start_index: int, data_format: int, messages_bytes: typing.List[typing.Any]) -> None:
|
189
|
-
...
|
190
|
-
|
191
|
-
async def aio(self, *args, **kwargs) -> None:
|
192
|
-
...
|
193
|
-
|
194
|
-
put_data_out: __put_data_out_spec
|
195
|
-
|
196
|
-
class __generator_output_task_spec(typing_extensions.Protocol):
|
197
|
-
def __call__(self, function_call_id: str, data_format: int, message_rx: asyncio.queues.Queue) -> None:
|
198
|
-
...
|
199
|
-
|
200
|
-
async def aio(self, *args, **kwargs) -> None:
|
201
|
-
...
|
202
|
-
|
203
|
-
generator_output_task: __generator_output_task_spec
|
204
|
-
|
205
|
-
class ___queue_create_spec(typing_extensions.Protocol):
|
206
|
-
def __call__(self, size: int) -> asyncio.queues.Queue:
|
207
|
-
...
|
208
|
-
|
209
|
-
async def aio(self, *args, **kwargs) -> asyncio.queues.Queue:
|
210
|
-
...
|
211
|
-
|
212
|
-
_queue_create: ___queue_create_spec
|
213
|
-
|
214
|
-
class ___queue_put_spec(typing_extensions.Protocol):
|
215
|
-
def __call__(self, queue: asyncio.queues.Queue, value: typing.Any) -> None:
|
216
|
-
...
|
217
|
-
|
218
|
-
async def aio(self, *args, **kwargs) -> None:
|
219
|
-
...
|
220
|
-
|
221
|
-
_queue_put: ___queue_put_spec
|
222
|
-
|
223
|
-
class __populate_input_blobs_spec(typing_extensions.Protocol):
|
224
|
-
def __call__(self, item: modal_proto.api_pb2.FunctionInput):
|
225
|
-
...
|
226
|
-
|
227
|
-
async def aio(self, *args, **kwargs):
|
228
|
-
...
|
229
|
-
|
230
|
-
populate_input_blobs: __populate_input_blobs_spec
|
231
|
-
|
232
|
-
def get_average_call_time(self) -> float:
|
233
|
-
...
|
234
|
-
|
235
|
-
def get_max_inputs_to_fetch(self):
|
236
|
-
...
|
237
|
-
|
238
|
-
class ___generate_inputs_spec(typing_extensions.Protocol):
|
239
|
-
def __call__(self) -> typing.Iterator[typing.Tuple[str, str, modal_proto.api_pb2.FunctionInput]]:
|
240
|
-
...
|
241
|
-
|
242
|
-
def aio(self) -> typing.AsyncIterator[typing.Tuple[str, str, modal_proto.api_pb2.FunctionInput]]:
|
243
|
-
...
|
244
|
-
|
245
|
-
_generate_inputs: ___generate_inputs_spec
|
246
|
-
|
247
|
-
class __run_inputs_outputs_spec(typing_extensions.Protocol):
|
248
|
-
def __call__(self, input_concurrency: int = 1) -> typing.Iterator[typing.Tuple[str, str, typing.Any, typing.Any]]:
|
249
|
-
...
|
250
|
-
|
251
|
-
def aio(self, input_concurrency: int = 1) -> typing.AsyncIterator[typing.Tuple[str, str, typing.Any, typing.Any]]:
|
252
|
-
...
|
253
|
-
|
254
|
-
run_inputs_outputs: __run_inputs_outputs_spec
|
255
|
-
|
256
|
-
class ___push_output_spec(typing_extensions.Protocol):
|
257
|
-
def __call__(self, input_id, started_at: float, data_format=0, **kwargs):
|
258
|
-
...
|
259
|
-
|
260
|
-
async def aio(self, *args, **kwargs):
|
261
|
-
...
|
262
|
-
|
263
|
-
_push_output: ___push_output_spec
|
264
|
-
|
265
|
-
def serialize_exception(self, exc: BaseException) -> typing.Union[bytes, None]:
|
266
|
-
...
|
267
|
-
|
268
|
-
def serialize_traceback(self, exc: BaseException) -> typing.Tuple[typing.Union[bytes, None], typing.Union[bytes, None]]:
|
269
|
-
...
|
270
|
-
|
271
|
-
class __handle_user_exception_spec(typing_extensions.Protocol):
|
272
|
-
def __call__(self) -> typing.Generator[None, None, None]:
|
273
|
-
...
|
274
|
-
|
275
|
-
def aio(self) -> typing.AsyncGenerator[None, None]:
|
276
|
-
...
|
277
|
-
|
278
|
-
handle_user_exception: __handle_user_exception_spec
|
279
|
-
|
280
|
-
class __handle_input_exception_spec(typing_extensions.Protocol):
|
281
|
-
def __call__(self, input_id, started_at: float) -> typing.Generator[None, None, None]:
|
282
|
-
...
|
283
|
-
|
284
|
-
def aio(self, input_id, started_at: float) -> typing.AsyncGenerator[None, None]:
|
285
|
-
...
|
286
|
-
|
287
|
-
handle_input_exception: __handle_input_exception_spec
|
288
|
-
|
289
|
-
class __complete_call_spec(typing_extensions.Protocol):
|
290
|
-
def __call__(self, started_at):
|
291
|
-
...
|
292
|
-
|
293
|
-
async def aio(self, *args, **kwargs):
|
294
|
-
...
|
295
|
-
|
296
|
-
complete_call: __complete_call_spec
|
297
|
-
|
298
|
-
class __push_output_spec(typing_extensions.Protocol):
|
299
|
-
def __call__(self, input_id, started_at: float, data: typing.Any, data_format: int) -> None:
|
300
|
-
...
|
301
|
-
|
302
|
-
async def aio(self, *args, **kwargs) -> None:
|
303
|
-
...
|
304
|
-
|
305
|
-
push_output: __push_output_spec
|
306
|
-
|
307
|
-
class __restore_spec(typing_extensions.Protocol):
|
308
|
-
def __call__(self) -> None:
|
309
|
-
...
|
310
|
-
|
311
|
-
async def aio(self, *args, **kwargs) -> None:
|
312
|
-
...
|
313
|
-
|
314
|
-
restore: __restore_spec
|
315
|
-
|
316
|
-
class __checkpoint_spec(typing_extensions.Protocol):
|
317
|
-
def __call__(self) -> None:
|
318
|
-
...
|
319
|
-
|
320
|
-
async def aio(self, *args, **kwargs) -> None:
|
321
|
-
...
|
322
|
-
|
323
|
-
checkpoint: __checkpoint_spec
|
324
|
-
|
325
|
-
class __volume_commit_spec(typing_extensions.Protocol):
|
326
|
-
def __call__(self, volume_ids: typing.List[str]) -> None:
|
327
|
-
...
|
328
|
-
|
329
|
-
async def aio(self, *args, **kwargs) -> None:
|
330
|
-
...
|
331
|
-
|
332
|
-
volume_commit: __volume_commit_spec
|
333
|
-
|
334
|
-
|
335
|
-
def call_function_sync(function_io_manager, imp_fun: ImportedFunction):
|
336
|
-
...
|
337
|
-
|
338
|
-
|
339
|
-
async def call_function_async(function_io_manager, imp_fun: ImportedFunction):
|
340
|
-
...
|
341
|
-
|
342
|
-
|
343
|
-
class ImportedFunction:
|
344
|
-
obj: typing.Any
|
345
|
-
fun: typing.Callable
|
346
|
-
stub: typing.Union[modal.stub._Stub, None]
|
347
|
-
is_async: bool
|
348
|
-
is_generator: bool
|
349
|
-
data_format: int
|
350
|
-
input_concurrency: int
|
351
|
-
is_auto_snapshot: bool
|
352
|
-
function: modal.functions._Function
|
353
|
-
|
354
|
-
def __init__(self, obj: typing.Any, fun: typing.Callable, stub: typing.Union[modal.stub._Stub, None], is_async: bool, is_generator: bool, data_format: int, input_concurrency: int, is_auto_snapshot: bool, function: modal.functions._Function) -> None:
|
355
|
-
...
|
356
|
-
|
357
|
-
def __repr__(self):
|
358
|
-
...
|
359
|
-
|
360
|
-
def __eq__(self, other):
|
361
|
-
...
|
362
|
-
|
363
|
-
|
364
|
-
def import_function(function_def: modal_proto.api_pb2.Function, ser_cls, ser_fun, ser_params: typing.Union[bytes, None], function_io_manager, client: modal.client.Client) -> ImportedFunction:
|
365
|
-
...
|
366
|
-
|
367
|
-
|
368
|
-
def call_lifecycle_functions(event_loop: UserCodeEventLoop, function_io_manager, funcs: collections.abc.Iterable[typing.Callable]) -> None:
|
369
|
-
...
|
370
|
-
|
371
|
-
|
372
|
-
def main(container_args: modal_proto.api_pb2.ContainerArguments, client: modal.client.Client):
|
373
|
-
...
|
374
|
-
|
375
|
-
|
376
|
-
MAX_OUTPUT_BATCH_SIZE: 'int'
|
377
|
-
|
378
|
-
RTT_S: 'float'
|
modal/_container_exec.py
DELETED
@@ -1,128 +0,0 @@
|
|
1
|
-
# Copyright Modal Labs 2024
|
2
|
-
import asyncio
|
3
|
-
import platform
|
4
|
-
from typing import List, Optional
|
5
|
-
|
6
|
-
import rich
|
7
|
-
import rich.status
|
8
|
-
from grpclib import Status
|
9
|
-
from grpclib.exceptions import GRPCError, StreamTerminatedError
|
10
|
-
from rich.console import Console
|
11
|
-
|
12
|
-
from modal_proto import api_pb2
|
13
|
-
|
14
|
-
from ._pty import get_pty_info
|
15
|
-
from ._utils.grpc_utils import RETRYABLE_GRPC_STATUS_CODES, retry_transient_errors, unary_stream
|
16
|
-
from ._utils.shell_utils import connect_to_terminal, write_to_fd
|
17
|
-
from .client import _Client
|
18
|
-
from .config import config
|
19
|
-
from .exception import NotFoundError
|
20
|
-
|
21
|
-
|
22
|
-
async def container_exec(task_id: str, command: List[str], *, pty: bool, client: _Client):
|
23
|
-
"""Execute a command inside an active container"""
|
24
|
-
if platform.system() == "Windows":
|
25
|
-
print("container exec is not currently supported on Windows.")
|
26
|
-
return
|
27
|
-
|
28
|
-
client = await _Client.from_env()
|
29
|
-
|
30
|
-
console = Console()
|
31
|
-
connecting_status = console.status("Connecting...")
|
32
|
-
connecting_status.start()
|
33
|
-
|
34
|
-
try:
|
35
|
-
res: api_pb2.ContainerExecResponse = await client.stub.ContainerExec(
|
36
|
-
api_pb2.ContainerExecRequest(
|
37
|
-
task_id=task_id,
|
38
|
-
command=command,
|
39
|
-
pty_info=get_pty_info(shell=True) if pty else None,
|
40
|
-
runtime_debug=config.get("function_runtime_debug"),
|
41
|
-
)
|
42
|
-
)
|
43
|
-
except GRPCError as err:
|
44
|
-
connecting_status.stop()
|
45
|
-
if err.status == Status.NOT_FOUND:
|
46
|
-
raise NotFoundError(f"Container ID {task_id} not found")
|
47
|
-
raise
|
48
|
-
|
49
|
-
await connect_to_exec(res.exec_id, pty, connecting_status)
|
50
|
-
|
51
|
-
|
52
|
-
async def connect_to_exec(exec_id: str, pty: bool = False, connecting_status: Optional[rich.status.Status] = None):
|
53
|
-
"""
|
54
|
-
Connects the current terminal to the given exec id.
|
55
|
-
|
56
|
-
If connecting_status is given, this function will stop the status spinner upon connection or error.
|
57
|
-
"""
|
58
|
-
|
59
|
-
client = await _Client.from_env()
|
60
|
-
|
61
|
-
async def _stream_to_stdout(on_connect: asyncio.Event) -> int:
|
62
|
-
return await _handle_exec_output(client, exec_id, on_connect)
|
63
|
-
|
64
|
-
async def _handle_input(data: bytes, message_index: int):
|
65
|
-
await retry_transient_errors(
|
66
|
-
client.stub.ContainerExecPutInput,
|
67
|
-
api_pb2.ContainerExecPutInputRequest(
|
68
|
-
exec_id=exec_id, input=api_pb2.RuntimeInputMessage(message=data, message_index=message_index)
|
69
|
-
),
|
70
|
-
total_timeout=10,
|
71
|
-
)
|
72
|
-
|
73
|
-
await connect_to_terminal(_handle_input, _stream_to_stdout, pty, connecting_status)
|
74
|
-
|
75
|
-
|
76
|
-
async def _handle_exec_output(client: _Client, exec_id: str, on_connect: Optional[asyncio.Event] = None) -> int:
|
77
|
-
"""
|
78
|
-
Streams exec output to current terminal's stdout.
|
79
|
-
|
80
|
-
The on_connect event will be set when the client connects to the running process,
|
81
|
-
and the event loop will be released.
|
82
|
-
|
83
|
-
Returns the status code of the process.
|
84
|
-
"""
|
85
|
-
|
86
|
-
last_batch_index = 0
|
87
|
-
exit_status = None
|
88
|
-
|
89
|
-
# we are connected if we received at least one message from the server
|
90
|
-
# (the server will send an empty message when the process spawns)
|
91
|
-
connected = False
|
92
|
-
|
93
|
-
async def _get_output():
|
94
|
-
nonlocal last_batch_index, exit_status, connected
|
95
|
-
req = api_pb2.ContainerExecGetOutputRequest(
|
96
|
-
exec_id=exec_id,
|
97
|
-
timeout=55,
|
98
|
-
last_batch_index=last_batch_index,
|
99
|
-
)
|
100
|
-
async for batch in unary_stream(client.stub.ContainerExecGetOutput, req):
|
101
|
-
for message in batch.items:
|
102
|
-
assert message.file_descriptor in [1, 2]
|
103
|
-
|
104
|
-
await write_to_fd(message.file_descriptor, str.encode(message.message))
|
105
|
-
|
106
|
-
if not connected:
|
107
|
-
connected = True
|
108
|
-
on_connect.set()
|
109
|
-
# give up the event loop
|
110
|
-
await asyncio.sleep(0)
|
111
|
-
|
112
|
-
if batch.HasField("exit_code"):
|
113
|
-
exit_status = batch.exit_code
|
114
|
-
break
|
115
|
-
last_batch_index = batch.batch_index
|
116
|
-
|
117
|
-
while exit_status is None:
|
118
|
-
try:
|
119
|
-
await _get_output()
|
120
|
-
except (GRPCError, StreamTerminatedError) as exc:
|
121
|
-
if isinstance(exc, GRPCError):
|
122
|
-
if exc.status in RETRYABLE_GRPC_STATUS_CODES:
|
123
|
-
continue
|
124
|
-
elif isinstance(exc, StreamTerminatedError):
|
125
|
-
continue
|
126
|
-
raise
|
127
|
-
|
128
|
-
return exit_status
|
modal/_sandbox_shell.py
DELETED
@@ -1,49 +0,0 @@
|
|
1
|
-
# Copyright Modal Labs 2024
|
2
|
-
import asyncio
|
3
|
-
|
4
|
-
from ._utils.shell_utils import connect_to_terminal, write_to_fd
|
5
|
-
from .sandbox import _Sandbox
|
6
|
-
|
7
|
-
|
8
|
-
async def connect_to_sandbox(sandbox: _Sandbox):
|
9
|
-
"""
|
10
|
-
Connects the current terminal to the Sandbox process.
|
11
|
-
"""
|
12
|
-
|
13
|
-
async def _handle_input(data: bytes, _):
|
14
|
-
sandbox.stdin.write(data)
|
15
|
-
await sandbox.stdin.drain.aio() # type: ignore
|
16
|
-
|
17
|
-
async def _stream_to_stdout(on_connect: asyncio.Event) -> int:
|
18
|
-
return await _stream_logs_to_stdout(sandbox, on_connect)
|
19
|
-
|
20
|
-
await connect_to_terminal(_handle_input, _stream_to_stdout, pty=True)
|
21
|
-
|
22
|
-
|
23
|
-
async def _stream_logs_to_stdout(sandbox: _Sandbox, on_connect: asyncio.Event) -> int:
|
24
|
-
"""
|
25
|
-
Streams sandbox output logs to the current terminal's stdout.
|
26
|
-
|
27
|
-
The on_connect event will be set when the client connects to the running process,
|
28
|
-
and the event loop will be released.
|
29
|
-
"""
|
30
|
-
|
31
|
-
# we are connected if we received at least one message from the server
|
32
|
-
# (the server will send an empty message when the process spawns)
|
33
|
-
connected = False
|
34
|
-
|
35
|
-
# Since the sandbox process will run in a PTY, stderr will go to the PTY
|
36
|
-
# slave. The PTY shell will then relay data from PTY master to stdout.
|
37
|
-
# Therefore, we only need to stream from/to stdout here.
|
38
|
-
async for message in sandbox.stdout:
|
39
|
-
await write_to_fd(1, message.encode("utf-8"))
|
40
|
-
|
41
|
-
if not connected:
|
42
|
-
connected = True
|
43
|
-
on_connect.set()
|
44
|
-
# give up the event loop
|
45
|
-
await asyncio.sleep(0)
|
46
|
-
|
47
|
-
# Right now we don't propagate the exit_status to the TaskLogs, so setting
|
48
|
-
# exit status to 0.
|
49
|
-
return 0
|
modal/shared_volume.py
DELETED
@@ -1,23 +0,0 @@
|
|
1
|
-
# Copyright Modal Labs 2023
|
2
|
-
|
3
|
-
from ._utils.async_utils import synchronize_api
|
4
|
-
from .exception import deprecation_error
|
5
|
-
|
6
|
-
|
7
|
-
class _SharedVolume:
|
8
|
-
def __init__(self, *args, **kwargs):
|
9
|
-
"""`SharedVolume` is deprecated. We recommend `Volume` (https://modal.com/docs/guide/volumes) instead."""
|
10
|
-
deprecation_error((2023, 7, 5), _SharedVolume.__init__.__doc__)
|
11
|
-
|
12
|
-
@staticmethod
|
13
|
-
def new(*args, **kwargs):
|
14
|
-
"""`SharedVolume` is deprecated. We recommend `Volume` (https://modal.com/docs/guide/volumes) instead."""
|
15
|
-
deprecation_error((2023, 7, 5), _SharedVolume.new.__doc__)
|
16
|
-
|
17
|
-
@staticmethod
|
18
|
-
def persisted(*args, **kwargs):
|
19
|
-
"""`SharedVolume` is deprecated. We recommend `Volume` (https://modal.com/docs/guide/volumes) instead."""
|
20
|
-
deprecation_error((2023, 7, 5), _SharedVolume.persisted.__doc__)
|
21
|
-
|
22
|
-
|
23
|
-
SharedVolume = synchronize_api(_SharedVolume)
|
modal/shared_volume.pyi
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
class _SharedVolume:
|
2
|
-
def __init__(self, *args, **kwargs):
|
3
|
-
...
|
4
|
-
|
5
|
-
@staticmethod
|
6
|
-
def new(*args, **kwargs):
|
7
|
-
...
|
8
|
-
|
9
|
-
@staticmethod
|
10
|
-
def persisted(*args, **kwargs):
|
11
|
-
...
|
12
|
-
|
13
|
-
|
14
|
-
class SharedVolume:
|
15
|
-
def __init__(self, *args, **kwargs):
|
16
|
-
...
|
17
|
-
|
18
|
-
@staticmethod
|
19
|
-
def new(*args, **kwargs):
|
20
|
-
...
|
21
|
-
|
22
|
-
@staticmethod
|
23
|
-
def persisted(*args, **kwargs):
|
24
|
-
...
|