modal 1.0.3.dev10__py3-none-any.whl → 1.2.3.dev7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of modal might be problematic. Click here for more details.
- modal/__init__.py +0 -2
- modal/__main__.py +3 -4
- modal/_billing.py +80 -0
- modal/_clustered_functions.py +7 -3
- modal/_clustered_functions.pyi +15 -3
- modal/_container_entrypoint.py +51 -69
- modal/_functions.py +508 -240
- modal/_grpc_client.py +171 -0
- modal/_load_context.py +105 -0
- modal/_object.py +81 -21
- modal/_output.py +58 -45
- modal/_partial_function.py +48 -73
- modal/_pty.py +7 -3
- modal/_resolver.py +26 -46
- modal/_runtime/asgi.py +4 -3
- modal/_runtime/container_io_manager.py +358 -220
- modal/_runtime/container_io_manager.pyi +296 -101
- modal/_runtime/execution_context.py +18 -2
- modal/_runtime/execution_context.pyi +64 -7
- modal/_runtime/gpu_memory_snapshot.py +262 -57
- modal/_runtime/user_code_imports.py +28 -58
- modal/_serialization.py +90 -6
- modal/_traceback.py +42 -1
- modal/_tunnel.pyi +380 -12
- modal/_utils/async_utils.py +84 -29
- modal/_utils/auth_token_manager.py +111 -0
- modal/_utils/blob_utils.py +181 -58
- modal/_utils/deprecation.py +19 -0
- modal/_utils/function_utils.py +91 -47
- modal/_utils/grpc_utils.py +89 -66
- modal/_utils/mount_utils.py +26 -1
- modal/_utils/name_utils.py +17 -3
- modal/_utils/task_command_router_client.py +536 -0
- modal/_utils/time_utils.py +34 -6
- modal/app.py +256 -88
- modal/app.pyi +909 -92
- modal/billing.py +5 -0
- modal/builder/2025.06.txt +18 -0
- modal/builder/PREVIEW.txt +18 -0
- modal/builder/base-images.json +58 -0
- modal/cli/_download.py +19 -3
- modal/cli/_traceback.py +3 -2
- modal/cli/app.py +4 -4
- modal/cli/cluster.py +15 -7
- modal/cli/config.py +5 -3
- modal/cli/container.py +7 -6
- modal/cli/dict.py +22 -16
- modal/cli/entry_point.py +12 -5
- modal/cli/environment.py +5 -4
- modal/cli/import_refs.py +3 -3
- modal/cli/launch.py +102 -5
- modal/cli/network_file_system.py +11 -12
- modal/cli/profile.py +3 -2
- modal/cli/programs/launch_instance_ssh.py +94 -0
- modal/cli/programs/run_jupyter.py +1 -1
- modal/cli/programs/run_marimo.py +95 -0
- modal/cli/programs/vscode.py +1 -1
- modal/cli/queues.py +57 -26
- modal/cli/run.py +91 -23
- modal/cli/secret.py +48 -22
- modal/cli/token.py +7 -8
- modal/cli/utils.py +4 -7
- modal/cli/volume.py +31 -25
- modal/client.py +15 -85
- modal/client.pyi +183 -62
- modal/cloud_bucket_mount.py +5 -3
- modal/cloud_bucket_mount.pyi +197 -5
- modal/cls.py +200 -126
- modal/cls.pyi +446 -68
- modal/config.py +29 -11
- modal/container_process.py +319 -19
- modal/container_process.pyi +190 -20
- modal/dict.py +290 -71
- modal/dict.pyi +835 -83
- modal/environments.py +15 -27
- modal/environments.pyi +46 -24
- modal/exception.py +14 -2
- modal/experimental/__init__.py +194 -40
- modal/experimental/flash.py +618 -0
- modal/experimental/flash.pyi +380 -0
- modal/experimental/ipython.py +11 -7
- modal/file_io.py +29 -36
- modal/file_io.pyi +251 -53
- modal/file_pattern_matcher.py +56 -16
- modal/functions.pyi +673 -92
- modal/gpu.py +1 -1
- modal/image.py +528 -176
- modal/image.pyi +1572 -145
- modal/io_streams.py +458 -128
- modal/io_streams.pyi +433 -52
- modal/mount.py +216 -151
- modal/mount.pyi +225 -78
- modal/network_file_system.py +45 -62
- modal/network_file_system.pyi +277 -56
- modal/object.pyi +93 -17
- modal/parallel_map.py +942 -129
- modal/parallel_map.pyi +294 -15
- modal/partial_function.py +0 -2
- modal/partial_function.pyi +234 -19
- modal/proxy.py +17 -8
- modal/proxy.pyi +36 -3
- modal/queue.py +270 -65
- modal/queue.pyi +817 -57
- modal/runner.py +115 -101
- modal/runner.pyi +205 -49
- modal/sandbox.py +512 -136
- modal/sandbox.pyi +845 -111
- modal/schedule.py +1 -1
- modal/secret.py +300 -70
- modal/secret.pyi +589 -34
- modal/serving.py +7 -11
- modal/serving.pyi +7 -8
- modal/snapshot.py +11 -8
- modal/snapshot.pyi +25 -4
- modal/token_flow.py +4 -4
- modal/token_flow.pyi +28 -8
- modal/volume.py +416 -158
- modal/volume.pyi +1117 -121
- {modal-1.0.3.dev10.dist-info → modal-1.2.3.dev7.dist-info}/METADATA +10 -9
- modal-1.2.3.dev7.dist-info/RECORD +195 -0
- modal_docs/mdmd/mdmd.py +17 -4
- modal_proto/api.proto +534 -79
- modal_proto/api_grpc.py +337 -1
- modal_proto/api_pb2.py +1522 -968
- modal_proto/api_pb2.pyi +1619 -134
- modal_proto/api_pb2_grpc.py +699 -4
- modal_proto/api_pb2_grpc.pyi +226 -14
- modal_proto/modal_api_grpc.py +175 -154
- modal_proto/sandbox_router.proto +145 -0
- modal_proto/sandbox_router_grpc.py +105 -0
- modal_proto/sandbox_router_pb2.py +149 -0
- modal_proto/sandbox_router_pb2.pyi +333 -0
- modal_proto/sandbox_router_pb2_grpc.py +203 -0
- modal_proto/sandbox_router_pb2_grpc.pyi +75 -0
- modal_proto/task_command_router.proto +144 -0
- modal_proto/task_command_router_grpc.py +105 -0
- modal_proto/task_command_router_pb2.py +149 -0
- modal_proto/task_command_router_pb2.pyi +333 -0
- modal_proto/task_command_router_pb2_grpc.py +203 -0
- modal_proto/task_command_router_pb2_grpc.pyi +75 -0
- modal_version/__init__.py +1 -1
- modal/requirements/PREVIEW.txt +0 -16
- modal/requirements/base-images.json +0 -26
- modal-1.0.3.dev10.dist-info/RECORD +0 -179
- modal_proto/modal_options_grpc.py +0 -3
- modal_proto/options.proto +0 -19
- modal_proto/options_grpc.py +0 -3
- modal_proto/options_pb2.py +0 -35
- modal_proto/options_pb2.pyi +0 -20
- modal_proto/options_pb2_grpc.py +0 -4
- modal_proto/options_pb2_grpc.pyi +0 -7
- /modal/{requirements → builder}/2023.12.312.txt +0 -0
- /modal/{requirements → builder}/2023.12.txt +0 -0
- /modal/{requirements → builder}/2024.04.txt +0 -0
- /modal/{requirements → builder}/2024.10.txt +0 -0
- /modal/{requirements → builder}/README.md +0 -0
- {modal-1.0.3.dev10.dist-info → modal-1.2.3.dev7.dist-info}/WHEEL +0 -0
- {modal-1.0.3.dev10.dist-info → modal-1.2.3.dev7.dist-info}/entry_points.txt +0 -0
- {modal-1.0.3.dev10.dist-info → modal-1.2.3.dev7.dist-info}/licenses/LICENSE +0 -0
- {modal-1.0.3.dev10.dist-info → modal-1.2.3.dev7.dist-info}/top_level.txt +0 -0
modal/parallel_map.pyi
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import asyncio.events
|
|
3
|
+
import asyncio.queues
|
|
3
4
|
import collections.abc
|
|
4
5
|
import enum
|
|
5
6
|
import modal._functions
|
|
6
7
|
import modal._utils.async_utils
|
|
8
|
+
import modal._utils.grpc_utils
|
|
7
9
|
import modal.client
|
|
8
10
|
import modal.functions
|
|
9
11
|
import modal.retries
|
|
@@ -12,6 +14,7 @@ import typing
|
|
|
12
14
|
import typing_extensions
|
|
13
15
|
|
|
14
16
|
class _SynchronizedQueue:
|
|
17
|
+
"""mdmd:hidden"""
|
|
15
18
|
async def init(self): ...
|
|
16
19
|
async def put(self, item): ...
|
|
17
20
|
async def get(self): ...
|
|
@@ -19,7 +22,10 @@ class _SynchronizedQueue:
|
|
|
19
22
|
SUPERSELF = typing.TypeVar("SUPERSELF", covariant=True)
|
|
20
23
|
|
|
21
24
|
class SynchronizedQueue:
|
|
22
|
-
|
|
25
|
+
"""mdmd:hidden"""
|
|
26
|
+
def __init__(self, /, *args, **kwargs):
|
|
27
|
+
"""Initialize self. See help(type(self)) for accurate signature."""
|
|
28
|
+
...
|
|
23
29
|
|
|
24
30
|
class __init_spec(typing_extensions.Protocol[SUPERSELF]):
|
|
25
31
|
def __call__(self, /): ...
|
|
@@ -40,34 +46,156 @@ class SynchronizedQueue:
|
|
|
40
46
|
get: __get_spec[typing_extensions.Self]
|
|
41
47
|
|
|
42
48
|
class _OutputValue:
|
|
49
|
+
"""_OutputValue(value: Any)"""
|
|
50
|
+
|
|
43
51
|
value: typing.Any
|
|
44
52
|
|
|
45
|
-
def __init__(self, value: typing.Any) -> None:
|
|
46
|
-
|
|
47
|
-
|
|
53
|
+
def __init__(self, value: typing.Any) -> None:
|
|
54
|
+
"""Initialize self. See help(type(self)) for accurate signature."""
|
|
55
|
+
...
|
|
56
|
+
|
|
57
|
+
def __repr__(self):
|
|
58
|
+
"""Return repr(self)."""
|
|
59
|
+
...
|
|
60
|
+
|
|
61
|
+
def __eq__(self, other):
|
|
62
|
+
"""Return self==value."""
|
|
63
|
+
...
|
|
64
|
+
|
|
65
|
+
class InputPreprocessor:
|
|
66
|
+
"""Constructs FunctionPutInputsItem objects from the raw-input queue, and puts them in the processed-input queue."""
|
|
67
|
+
def __init__(
|
|
68
|
+
self,
|
|
69
|
+
client: modal.client._Client,
|
|
70
|
+
*,
|
|
71
|
+
raw_input_queue: _SynchronizedQueue,
|
|
72
|
+
processed_input_queue: asyncio.queues.Queue,
|
|
73
|
+
function: modal._functions._Function,
|
|
74
|
+
created_callback: collections.abc.Callable[[int], None],
|
|
75
|
+
done_callback: collections.abc.Callable[[], None],
|
|
76
|
+
):
|
|
77
|
+
"""Initialize self. See help(type(self)) for accurate signature."""
|
|
78
|
+
...
|
|
79
|
+
|
|
80
|
+
def input_iter(self): ...
|
|
81
|
+
def create_input_factory(self): ...
|
|
82
|
+
def drain_input_generator(self): ...
|
|
83
|
+
|
|
84
|
+
class InputPumper:
|
|
85
|
+
"""Reads inputs from a queue of FunctionPutInputsItems, and sends them to the server."""
|
|
86
|
+
def __init__(
|
|
87
|
+
self,
|
|
88
|
+
client: modal.client._Client,
|
|
89
|
+
*,
|
|
90
|
+
input_queue: asyncio.queues.Queue,
|
|
91
|
+
function: modal._functions._Function,
|
|
92
|
+
function_call_id: str,
|
|
93
|
+
max_batch_size: int,
|
|
94
|
+
map_items_manager: typing.Optional[_MapItemsManager] = None,
|
|
95
|
+
):
|
|
96
|
+
"""Initialize self. See help(type(self)) for accurate signature."""
|
|
97
|
+
...
|
|
98
|
+
|
|
99
|
+
def pump_inputs(self): ...
|
|
100
|
+
@property
|
|
101
|
+
def _function_inputs_retry(self) -> modal._utils.grpc_utils.Retry: ...
|
|
102
|
+
|
|
103
|
+
class SyncInputPumper(InputPumper):
|
|
104
|
+
"""Reads inputs from a queue of FunctionPutInputsItems, and sends them to the server."""
|
|
105
|
+
def __init__(
|
|
106
|
+
self,
|
|
107
|
+
client: modal.client._Client,
|
|
108
|
+
*,
|
|
109
|
+
input_queue: asyncio.queues.Queue,
|
|
110
|
+
retry_queue: modal._utils.async_utils.TimestampPriorityQueue,
|
|
111
|
+
function: modal._functions._Function,
|
|
112
|
+
function_call_jwt: str,
|
|
113
|
+
function_call_id: str,
|
|
114
|
+
map_items_manager: _MapItemsManager,
|
|
115
|
+
):
|
|
116
|
+
"""Initialize self. See help(type(self)) for accurate signature."""
|
|
117
|
+
...
|
|
118
|
+
|
|
119
|
+
def retry_inputs(self): ...
|
|
120
|
+
|
|
121
|
+
class AsyncInputPumper(InputPumper):
|
|
122
|
+
"""Reads inputs from a queue of FunctionPutInputsItems, and sends them to the server."""
|
|
123
|
+
def __init__(
|
|
124
|
+
self,
|
|
125
|
+
client: modal.client._Client,
|
|
126
|
+
*,
|
|
127
|
+
input_queue: asyncio.queues.Queue,
|
|
128
|
+
function: modal._functions._Function,
|
|
129
|
+
function_call_id: str,
|
|
130
|
+
):
|
|
131
|
+
"""Initialize self. See help(type(self)) for accurate signature."""
|
|
132
|
+
...
|
|
48
133
|
|
|
134
|
+
def pump_inputs(self): ...
|
|
135
|
+
|
|
136
|
+
async def _spawn_map_invocation(
|
|
137
|
+
function: modal._functions._Function, raw_input_queue: _SynchronizedQueue, client: modal.client._Client
|
|
138
|
+
) -> tuple[str, int]: ...
|
|
49
139
|
def _map_invocation(
|
|
50
140
|
function: modal._functions._Function,
|
|
51
141
|
raw_input_queue: _SynchronizedQueue,
|
|
52
142
|
client: modal.client._Client,
|
|
53
143
|
order_outputs: bool,
|
|
54
144
|
return_exceptions: bool,
|
|
145
|
+
wrap_returned_exceptions: bool,
|
|
55
146
|
count_update_callback: typing.Optional[collections.abc.Callable[[int, int], None]],
|
|
56
147
|
function_call_invocation_type: int,
|
|
57
148
|
): ...
|
|
149
|
+
def _map_invocation_inputplane(
|
|
150
|
+
function: modal._functions._Function,
|
|
151
|
+
raw_input_queue: _SynchronizedQueue,
|
|
152
|
+
client: modal.client._Client,
|
|
153
|
+
order_outputs: bool,
|
|
154
|
+
return_exceptions: bool,
|
|
155
|
+
wrap_returned_exceptions: bool,
|
|
156
|
+
count_update_callback: typing.Optional[collections.abc.Callable[[int, int], None]],
|
|
157
|
+
) -> typing.AsyncGenerator[typing.Any, None]:
|
|
158
|
+
"""Input-plane implementation of a function map invocation.
|
|
159
|
+
|
|
160
|
+
This is analogous to `_map_invocation`, but instead of the control-plane
|
|
161
|
+
`FunctionMap` / `FunctionPutInputs` / `FunctionGetOutputs` RPCs it speaks
|
|
162
|
+
the input-plane protocol consisting of `MapStartOrContinue`, `MapAwait`, and `MapCheckInputs`.
|
|
163
|
+
"""
|
|
164
|
+
...
|
|
165
|
+
|
|
58
166
|
def _map_helper(
|
|
59
167
|
self: modal.functions.Function,
|
|
60
168
|
async_input_gen: typing.AsyncGenerator[typing.Any, None],
|
|
61
169
|
kwargs={},
|
|
62
170
|
order_outputs: bool = True,
|
|
63
171
|
return_exceptions: bool = False,
|
|
64
|
-
|
|
172
|
+
wrap_returned_exceptions: bool = True,
|
|
173
|
+
) -> typing.AsyncGenerator[typing.Any, None]:
|
|
174
|
+
"""Core implementation that supports `_map_async()`, `_starmap_async()` and `_for_each_async()`.
|
|
175
|
+
|
|
176
|
+
Runs in an event loop on the main thread. Concurrently feeds new input to the input queue and yields available
|
|
177
|
+
outputs to the caller.
|
|
178
|
+
|
|
179
|
+
Note that since the iterator(s) can block, it's a bit opaque how often the event
|
|
180
|
+
loop decides to get a new input vs how often it will emit a new output.
|
|
181
|
+
|
|
182
|
+
We could make this explicit as an improvement or even let users decide what they
|
|
183
|
+
prefer: throughput (prioritize queueing inputs) or latency (prioritize yielding results)
|
|
184
|
+
"""
|
|
185
|
+
...
|
|
186
|
+
|
|
187
|
+
def _maybe_warn_about_exceptions(func_name: str, return_exceptions: bool, wrap_returned_exceptions: bool): ...
|
|
188
|
+
def _invoked_from_sync_wrapper() -> bool:
|
|
189
|
+
"""Check whether the calling function was called from a sync wrapper."""
|
|
190
|
+
...
|
|
191
|
+
|
|
65
192
|
def _map_async(
|
|
66
193
|
self: modal.functions.Function,
|
|
67
194
|
*input_iterators: typing.Union[typing.Iterable[typing.Any], typing.AsyncIterable[typing.Any]],
|
|
68
195
|
kwargs={},
|
|
69
196
|
order_outputs: bool = True,
|
|
70
197
|
return_exceptions: bool = False,
|
|
198
|
+
wrap_returned_exceptions: bool = True,
|
|
71
199
|
) -> typing.AsyncGenerator[typing.Any, None]: ...
|
|
72
200
|
def _starmap_async(
|
|
73
201
|
self,
|
|
@@ -78,14 +206,118 @@ def _starmap_async(
|
|
|
78
206
|
kwargs={},
|
|
79
207
|
order_outputs: bool = True,
|
|
80
208
|
return_exceptions: bool = False,
|
|
209
|
+
wrap_returned_exceptions: bool = True,
|
|
81
210
|
) -> typing.AsyncIterable[typing.Any]: ...
|
|
82
211
|
async def _for_each_async(self, *input_iterators, kwargs={}, ignore_exceptions: bool = False) -> None: ...
|
|
83
212
|
def _map_sync(
|
|
84
|
-
self,
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
213
|
+
self,
|
|
214
|
+
*input_iterators,
|
|
215
|
+
kwargs={},
|
|
216
|
+
order_outputs: bool = True,
|
|
217
|
+
return_exceptions: bool = False,
|
|
218
|
+
wrap_returned_exceptions: bool = True,
|
|
219
|
+
) -> modal._utils.async_utils.AsyncOrSyncIterable:
|
|
220
|
+
"""Parallel map over a set of inputs.
|
|
221
|
+
|
|
222
|
+
Takes one iterator argument per argument in the function being mapped over.
|
|
223
|
+
|
|
224
|
+
Example:
|
|
225
|
+
```python
|
|
226
|
+
@app.function()
|
|
227
|
+
def my_func(a):
|
|
228
|
+
return a ** 2
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
@app.local_entrypoint()
|
|
232
|
+
def main():
|
|
233
|
+
assert list(my_func.map([1, 2, 3, 4])) == [1, 4, 9, 16]
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
If applied to a `app.function`, `map()` returns one result per input and the output order
|
|
237
|
+
is guaranteed to be the same as the input order. Set `order_outputs=False` to return results
|
|
238
|
+
in the order that they are completed instead.
|
|
239
|
+
|
|
240
|
+
`return_exceptions` can be used to treat exceptions as successful results:
|
|
241
|
+
|
|
242
|
+
```python
|
|
243
|
+
@app.function()
|
|
244
|
+
def my_func(a):
|
|
245
|
+
if a == 2:
|
|
246
|
+
raise Exception("ohno")
|
|
247
|
+
return a ** 2
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
@app.local_entrypoint()
|
|
251
|
+
def main():
|
|
252
|
+
# [0, 1, UserCodeException(Exception('ohno'))]
|
|
253
|
+
print(list(my_func.map(range(3), return_exceptions=True)))
|
|
254
|
+
```
|
|
255
|
+
"""
|
|
256
|
+
...
|
|
257
|
+
|
|
258
|
+
async def _experimental_spawn_map_async(self, *input_iterators, kwargs={}) -> modal._functions._FunctionCall: ...
|
|
259
|
+
async def _spawn_map_helper(
|
|
260
|
+
self: modal.functions.Function, async_input_gen, kwargs={}
|
|
261
|
+
) -> modal._functions._FunctionCall: ...
|
|
262
|
+
def _experimental_spawn_map_sync(self, *input_iterators, kwargs={}) -> modal._functions._FunctionCall:
|
|
263
|
+
"""mdmd:hidden
|
|
264
|
+
Spawn parallel execution over a set of inputs, returning as soon as the inputs are created.
|
|
265
|
+
|
|
266
|
+
Unlike `modal.Function.map`, this method does not block on completion of the remote execution but
|
|
267
|
+
returns a `modal.FunctionCall` object that can be used to poll status and retrieve results later.
|
|
268
|
+
|
|
269
|
+
Takes one iterator argument per argument in the function being mapped over.
|
|
270
|
+
|
|
271
|
+
Example:
|
|
272
|
+
```python
|
|
273
|
+
@app.function()
|
|
274
|
+
def my_func(a, b):
|
|
275
|
+
return a ** b
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
@app.local_entrypoint()
|
|
279
|
+
def main():
|
|
280
|
+
fc = my_func.spawn_map([1, 2], [3, 4])
|
|
281
|
+
```
|
|
282
|
+
"""
|
|
283
|
+
...
|
|
284
|
+
|
|
285
|
+
async def _spawn_map_async(self, *input_iterators, kwargs={}) -> None:
|
|
286
|
+
"""This runs in an event loop on the main thread. It consumes inputs from the input iterators and creates async
|
|
287
|
+
function calls for each.
|
|
288
|
+
"""
|
|
289
|
+
...
|
|
290
|
+
|
|
291
|
+
def _spawn_map_sync(self, *input_iterators, kwargs={}) -> None:
|
|
292
|
+
"""Spawn parallel execution over a set of inputs, exiting as soon as the inputs are created (without waiting
|
|
293
|
+
for the map to complete).
|
|
294
|
+
|
|
295
|
+
Takes one iterator argument per argument in the function being mapped over.
|
|
296
|
+
|
|
297
|
+
Example:
|
|
298
|
+
```python
|
|
299
|
+
@app.function()
|
|
300
|
+
def my_func(a):
|
|
301
|
+
return a ** 2
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
@app.local_entrypoint()
|
|
305
|
+
def main():
|
|
306
|
+
my_func.spawn_map([1, 2, 3, 4])
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
Programmatic retrieval of results will be supported in a future update.
|
|
310
|
+
"""
|
|
311
|
+
...
|
|
312
|
+
|
|
313
|
+
def _for_each_sync(self, *input_iterators, kwargs={}, ignore_exceptions: bool = False):
|
|
314
|
+
"""Execute function for all inputs, ignoring outputs. Waits for completion of the inputs.
|
|
315
|
+
|
|
316
|
+
Convenient alias for `.map()` in cases where the function just needs to be called.
|
|
317
|
+
as the caller doesn't have to consume the generator to process the inputs.
|
|
318
|
+
"""
|
|
319
|
+
...
|
|
320
|
+
|
|
89
321
|
def _starmap_sync(
|
|
90
322
|
self,
|
|
91
323
|
input_iterator: typing.Iterable[typing.Sequence[typing.Any]],
|
|
@@ -93,7 +325,25 @@ def _starmap_sync(
|
|
|
93
325
|
kwargs={},
|
|
94
326
|
order_outputs: bool = True,
|
|
95
327
|
return_exceptions: bool = False,
|
|
96
|
-
|
|
328
|
+
wrap_returned_exceptions: bool = True,
|
|
329
|
+
) -> modal._utils.async_utils.AsyncOrSyncIterable:
|
|
330
|
+
"""Like `map`, but spreads arguments over multiple function arguments.
|
|
331
|
+
|
|
332
|
+
Assumes every input is a sequence (e.g. a tuple).
|
|
333
|
+
|
|
334
|
+
Example:
|
|
335
|
+
```python
|
|
336
|
+
@app.function()
|
|
337
|
+
def my_func(a, b):
|
|
338
|
+
return a + b
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
@app.local_entrypoint()
|
|
342
|
+
def main():
|
|
343
|
+
assert list(my_func.starmap([(1, 2), (3, 4)])) == [3, 7]
|
|
344
|
+
```
|
|
345
|
+
"""
|
|
346
|
+
...
|
|
97
347
|
|
|
98
348
|
class _MapItemState(enum.Enum):
|
|
99
349
|
# The input is being sent the server with a PutInputs request, but the response has not been received yet.
|
|
@@ -130,7 +380,12 @@ class _MapItemContext:
|
|
|
130
380
|
input: modal_proto.api_pb2.FunctionInput,
|
|
131
381
|
retry_manager: modal.retries.RetryManager,
|
|
132
382
|
sync_client_retries_enabled: bool,
|
|
133
|
-
|
|
383
|
+
is_input_plane_instance: bool = False,
|
|
384
|
+
):
|
|
385
|
+
"""Initialize self. See help(type(self)) for accurate signature."""
|
|
386
|
+
...
|
|
387
|
+
|
|
388
|
+
def handle_map_start_or_continue_response(self, attempt_token: str): ...
|
|
134
389
|
def handle_put_inputs_response(self, item: modal_proto.api_pb2.FunctionPutInputsResponseItem): ...
|
|
135
390
|
async def handle_get_outputs_response(
|
|
136
391
|
self,
|
|
@@ -138,9 +393,17 @@ class _MapItemContext:
|
|
|
138
393
|
now_seconds: int,
|
|
139
394
|
function_call_invocation_type: int,
|
|
140
395
|
retry_queue: modal._utils.async_utils.TimestampPriorityQueue,
|
|
141
|
-
) -> _OutputType:
|
|
396
|
+
) -> _OutputType:
|
|
397
|
+
"""Processes the output, and determines if it is complete or needs to be retried.
|
|
398
|
+
|
|
399
|
+
Return True if input state was changed to COMPLETE, otherwise False.
|
|
400
|
+
"""
|
|
401
|
+
...
|
|
402
|
+
|
|
142
403
|
async def prepare_item_for_retry(self) -> modal_proto.api_pb2.FunctionRetryInputsItem: ...
|
|
404
|
+
def set_retry_policy(self, retry_policy: modal_proto.api_pb2.FunctionRetryPolicy): ...
|
|
143
405
|
def handle_retry_response(self, input_jwt: str): ...
|
|
406
|
+
async def create_map_start_or_continue_item(self, idx: int) -> modal_proto.api_pb2.MapStartOrContinueItem: ...
|
|
144
407
|
|
|
145
408
|
class _MapItemsManager:
|
|
146
409
|
def __init__(
|
|
@@ -150,16 +413,32 @@ class _MapItemsManager:
|
|
|
150
413
|
retry_queue: modal._utils.async_utils.TimestampPriorityQueue,
|
|
151
414
|
sync_client_retries_enabled: bool,
|
|
152
415
|
max_inputs_outstanding: int,
|
|
153
|
-
|
|
416
|
+
is_input_plane_instance: bool = False,
|
|
417
|
+
):
|
|
418
|
+
"""Initialize self. See help(type(self)) for accurate signature."""
|
|
419
|
+
...
|
|
420
|
+
|
|
421
|
+
def set_retry_policy(self, retry_policy: modal_proto.api_pb2.FunctionRetryPolicy): ...
|
|
154
422
|
async def add_items(self, items: list[modal_proto.api_pb2.FunctionPutInputsItem]): ...
|
|
423
|
+
async def add_items_inputplane(self, items: list[modal_proto.api_pb2.MapStartOrContinueItem]): ...
|
|
155
424
|
async def prepare_items_for_retry(
|
|
156
425
|
self, retriable_idxs: list[int]
|
|
157
426
|
) -> list[modal_proto.api_pb2.FunctionRetryInputsItem]: ...
|
|
158
|
-
def
|
|
427
|
+
def update_items_retry_policy(self, retry_policy: modal_proto.api_pb2.FunctionRetryPolicy): ...
|
|
428
|
+
def get_input_jwts_waiting_for_output(self) -> list[str]:
|
|
429
|
+
"""Returns a list of input_jwts for inputs that are waiting for output."""
|
|
430
|
+
...
|
|
431
|
+
|
|
432
|
+
def get_input_idxs_waiting_for_output(self) -> list[tuple[int, str]]:
|
|
433
|
+
"""Returns a list of input_idxs for inputs that are waiting for output."""
|
|
434
|
+
...
|
|
435
|
+
|
|
159
436
|
def _remove_item(self, item_idx: int): ...
|
|
160
437
|
def get_item_context(self, item_idx: int) -> _MapItemContext: ...
|
|
438
|
+
def handle_put_continue_response(self, items: list[tuple[int, str]]): ...
|
|
161
439
|
def handle_put_inputs_response(self, items: list[modal_proto.api_pb2.FunctionPutInputsResponseItem]): ...
|
|
162
440
|
def handle_retry_response(self, input_jwts: list[str]): ...
|
|
441
|
+
async def handle_check_inputs_response(self, response: list[tuple[int, bool]]): ...
|
|
163
442
|
async def handle_get_outputs_response(
|
|
164
443
|
self, item: modal_proto.api_pb2.FunctionGetOutputsItem, now_seconds: int
|
|
165
444
|
) -> _OutputType: ...
|
modal/partial_function.py
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
from ._partial_function import (
|
|
4
4
|
_asgi_app,
|
|
5
5
|
_batched,
|
|
6
|
-
_build,
|
|
7
6
|
_concurrent,
|
|
8
7
|
_enter,
|
|
9
8
|
_exit,
|
|
@@ -25,7 +24,6 @@ fastapi_endpoint = synchronize_api(_fastapi_endpoint, target_module=__name__)
|
|
|
25
24
|
asgi_app = synchronize_api(_asgi_app, target_module=__name__)
|
|
26
25
|
wsgi_app = synchronize_api(_wsgi_app, target_module=__name__)
|
|
27
26
|
web_server = synchronize_api(_web_server, target_module=__name__)
|
|
28
|
-
build = synchronize_api(_build, target_module=__name__)
|
|
29
27
|
enter = synchronize_api(_enter, target_module=__name__)
|
|
30
28
|
exit = synchronize_api(_exit, target_module=__name__)
|
|
31
29
|
batched = synchronize_api(_batched, target_module=__name__)
|