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/functions.pyi
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import collections.abc
|
|
2
2
|
import google.protobuf.message
|
|
3
3
|
import modal._functions
|
|
4
|
+
import modal._load_context
|
|
4
5
|
import modal._utils.async_utils
|
|
5
6
|
import modal._utils.function_utils
|
|
6
7
|
import modal.app
|
|
@@ -35,6 +36,12 @@ class Function(
|
|
|
35
36
|
typing.Generic[modal._functions.P, modal._functions.ReturnType, modal._functions.OriginalReturnType],
|
|
36
37
|
modal.object.Object,
|
|
37
38
|
):
|
|
39
|
+
"""Functions are the basic units of serverless execution on Modal.
|
|
40
|
+
|
|
41
|
+
Generally, you will not construct a `Function` directly. Instead, use the
|
|
42
|
+
`App.function()` decorator to register your Python functions with your App.
|
|
43
|
+
"""
|
|
44
|
+
|
|
38
45
|
_info: typing.Optional[modal._utils.function_utils.FunctionInfo]
|
|
39
46
|
_serve_mounts: frozenset[modal.mount.Mount]
|
|
40
47
|
_app: typing.Optional[modal.app.App]
|
|
@@ -53,13 +60,17 @@ class Function(
|
|
|
53
60
|
_method_handle_metadata: typing.Optional[dict[str, modal_proto.api_pb2.FunctionHandleMetadata]]
|
|
54
61
|
_metadata: typing.Optional[modal_proto.api_pb2.FunctionHandleMetadata]
|
|
55
62
|
|
|
56
|
-
def __init__(self, *args, **kwargs):
|
|
63
|
+
def __init__(self, *args, **kwargs):
|
|
64
|
+
"""mdmd:hidden"""
|
|
65
|
+
...
|
|
66
|
+
|
|
57
67
|
@staticmethod
|
|
58
68
|
def from_local(
|
|
59
69
|
info: modal._utils.function_utils.FunctionInfo,
|
|
60
|
-
app,
|
|
70
|
+
app: typing.Optional[modal.app.App],
|
|
61
71
|
image: modal.image.Image,
|
|
62
|
-
|
|
72
|
+
env: typing.Optional[dict[str, typing.Optional[str]]] = None,
|
|
73
|
+
secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
|
|
63
74
|
schedule: typing.Optional[modal.schedule.Schedule] = None,
|
|
64
75
|
is_generator: bool = False,
|
|
65
76
|
gpu: typing.Union[None, str, modal.gpu._GPUConfig, list[typing.Union[None, str, modal.gpu._GPUConfig]]] = None,
|
|
@@ -75,7 +86,8 @@ class Function(
|
|
|
75
86
|
memory: typing.Union[int, tuple[int, int], None] = None,
|
|
76
87
|
proxy: typing.Optional[modal.proxy.Proxy] = None,
|
|
77
88
|
retries: typing.Union[int, modal.retries.Retries, None] = None,
|
|
78
|
-
timeout:
|
|
89
|
+
timeout: int = 300,
|
|
90
|
+
startup_timeout: typing.Optional[int] = None,
|
|
79
91
|
min_containers: typing.Optional[int] = None,
|
|
80
92
|
max_containers: typing.Optional[int] = None,
|
|
81
93
|
buffer_containers: typing.Optional[int] = None,
|
|
@@ -96,19 +108,30 @@ class Function(
|
|
|
96
108
|
rdma: typing.Optional[bool] = None,
|
|
97
109
|
max_inputs: typing.Optional[int] = None,
|
|
98
110
|
ephemeral_disk: typing.Optional[int] = None,
|
|
99
|
-
include_source:
|
|
111
|
+
include_source: bool = True,
|
|
100
112
|
experimental_options: typing.Optional[dict[str, str]] = None,
|
|
101
113
|
_experimental_proxy_ip: typing.Optional[str] = None,
|
|
102
114
|
_experimental_custom_scaling_factor: typing.Optional[float] = None,
|
|
103
|
-
|
|
104
|
-
) -> Function:
|
|
115
|
+
restrict_output: bool = False,
|
|
116
|
+
) -> Function:
|
|
117
|
+
"""mdmd:hidden
|
|
118
|
+
|
|
119
|
+
Note: This is not intended to be public API.
|
|
120
|
+
"""
|
|
121
|
+
...
|
|
122
|
+
|
|
105
123
|
def _bind_parameters(
|
|
106
124
|
self,
|
|
107
125
|
obj: modal.cls.Obj,
|
|
108
126
|
options: typing.Optional[modal.cls._ServiceOptions],
|
|
109
127
|
args: collections.abc.Sized,
|
|
110
128
|
kwargs: dict[str, typing.Any],
|
|
111
|
-
) -> Function:
|
|
129
|
+
) -> Function:
|
|
130
|
+
"""mdmd:hidden
|
|
131
|
+
|
|
132
|
+
Binds a class-function to a specific instance of (init params, options) or a new workspace
|
|
133
|
+
"""
|
|
134
|
+
...
|
|
112
135
|
|
|
113
136
|
class __update_autoscaler_spec(typing_extensions.Protocol[SUPERSELF]):
|
|
114
137
|
def __call__(
|
|
@@ -119,7 +142,33 @@ class Function(
|
|
|
119
142
|
max_containers: typing.Optional[int] = None,
|
|
120
143
|
buffer_containers: typing.Optional[int] = None,
|
|
121
144
|
scaledown_window: typing.Optional[int] = None,
|
|
122
|
-
) -> None:
|
|
145
|
+
) -> None:
|
|
146
|
+
"""Override the current autoscaler behavior for this Function.
|
|
147
|
+
|
|
148
|
+
Unspecified parameters will retain their current value, i.e. either the static value
|
|
149
|
+
from the function decorator, or an override value from a previous call to this method.
|
|
150
|
+
|
|
151
|
+
Subsequent deployments of the App containing this Function will reset the autoscaler back to
|
|
152
|
+
its static configuration.
|
|
153
|
+
|
|
154
|
+
Examples:
|
|
155
|
+
|
|
156
|
+
```python notest
|
|
157
|
+
f = modal.Function.from_name("my-app", "function")
|
|
158
|
+
|
|
159
|
+
# Always have at least 2 containers running, with an extra buffer when the Function is active
|
|
160
|
+
f.update_autoscaler(min_containers=2, buffer_containers=1)
|
|
161
|
+
|
|
162
|
+
# Limit this Function to avoid spinning up more than 5 containers
|
|
163
|
+
f.update_autoscaler(max_containers=5)
|
|
164
|
+
|
|
165
|
+
# Extend the scaledown window to increase the amount of time that idle containers stay alive
|
|
166
|
+
f.update_autoscaler(scaledown_window=300)
|
|
167
|
+
|
|
168
|
+
```
|
|
169
|
+
"""
|
|
170
|
+
...
|
|
171
|
+
|
|
123
172
|
async def aio(
|
|
124
173
|
self,
|
|
125
174
|
/,
|
|
@@ -128,83 +177,215 @@ class Function(
|
|
|
128
177
|
max_containers: typing.Optional[int] = None,
|
|
129
178
|
buffer_containers: typing.Optional[int] = None,
|
|
130
179
|
scaledown_window: typing.Optional[int] = None,
|
|
131
|
-
) -> None:
|
|
180
|
+
) -> None:
|
|
181
|
+
"""Override the current autoscaler behavior for this Function.
|
|
182
|
+
|
|
183
|
+
Unspecified parameters will retain their current value, i.e. either the static value
|
|
184
|
+
from the function decorator, or an override value from a previous call to this method.
|
|
185
|
+
|
|
186
|
+
Subsequent deployments of the App containing this Function will reset the autoscaler back to
|
|
187
|
+
its static configuration.
|
|
188
|
+
|
|
189
|
+
Examples:
|
|
190
|
+
|
|
191
|
+
```python notest
|
|
192
|
+
f = modal.Function.from_name("my-app", "function")
|
|
193
|
+
|
|
194
|
+
# Always have at least 2 containers running, with an extra buffer when the Function is active
|
|
195
|
+
f.update_autoscaler(min_containers=2, buffer_containers=1)
|
|
196
|
+
|
|
197
|
+
# Limit this Function to avoid spinning up more than 5 containers
|
|
198
|
+
f.update_autoscaler(max_containers=5)
|
|
199
|
+
|
|
200
|
+
# Extend the scaledown window to increase the amount of time that idle containers stay alive
|
|
201
|
+
f.update_autoscaler(scaledown_window=300)
|
|
202
|
+
|
|
203
|
+
```
|
|
204
|
+
"""
|
|
205
|
+
...
|
|
132
206
|
|
|
133
207
|
update_autoscaler: __update_autoscaler_spec[typing_extensions.Self]
|
|
134
208
|
|
|
135
209
|
class __keep_warm_spec(typing_extensions.Protocol[SUPERSELF]):
|
|
136
|
-
def __call__(self, /, warm_pool_size: int) -> None:
|
|
137
|
-
|
|
210
|
+
def __call__(self, /, warm_pool_size: int) -> None:
|
|
211
|
+
"""mdmd:hidden
|
|
212
|
+
Set the warm pool size for the Function.
|
|
213
|
+
|
|
214
|
+
DEPRECATED: Please adapt your code to use the more general `update_autoscaler` method instead:
|
|
215
|
+
|
|
216
|
+
```python notest
|
|
217
|
+
f = modal.Function.from_name("my-app", "function")
|
|
218
|
+
|
|
219
|
+
# Old pattern (deprecated)
|
|
220
|
+
f.keep_warm(2)
|
|
221
|
+
|
|
222
|
+
# New pattern
|
|
223
|
+
f.update_autoscaler(min_containers=2)
|
|
224
|
+
```
|
|
225
|
+
"""
|
|
226
|
+
...
|
|
227
|
+
|
|
228
|
+
async def aio(self, /, warm_pool_size: int) -> None:
|
|
229
|
+
"""mdmd:hidden
|
|
230
|
+
Set the warm pool size for the Function.
|
|
231
|
+
|
|
232
|
+
DEPRECATED: Please adapt your code to use the more general `update_autoscaler` method instead:
|
|
233
|
+
|
|
234
|
+
```python notest
|
|
235
|
+
f = modal.Function.from_name("my-app", "function")
|
|
236
|
+
|
|
237
|
+
# Old pattern (deprecated)
|
|
238
|
+
f.keep_warm(2)
|
|
239
|
+
|
|
240
|
+
# New pattern
|
|
241
|
+
f.update_autoscaler(min_containers=2)
|
|
242
|
+
```
|
|
243
|
+
"""
|
|
244
|
+
...
|
|
138
245
|
|
|
139
246
|
keep_warm: __keep_warm_spec[typing_extensions.Self]
|
|
140
247
|
|
|
141
248
|
@classmethod
|
|
142
|
-
def _from_name(cls, app_name: str, name: str,
|
|
249
|
+
def _from_name(cls, app_name: str, name: str, *, load_context_overrides: modal._load_context.LoadContext): ...
|
|
143
250
|
@classmethod
|
|
144
251
|
def from_name(
|
|
145
|
-
cls: type[Function],
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
client: typing.Optional[modal.client.Client] = None,
|
|
165
|
-
environment_name: typing.Optional[str] = None,
|
|
166
|
-
) -> Function: ...
|
|
167
|
-
|
|
168
|
-
lookup: __lookup_spec
|
|
252
|
+
cls: type[Function],
|
|
253
|
+
app_name: str,
|
|
254
|
+
name: str,
|
|
255
|
+
*,
|
|
256
|
+
namespace=None,
|
|
257
|
+
environment_name: typing.Optional[str] = None,
|
|
258
|
+
client: typing.Optional[modal.client.Client] = None,
|
|
259
|
+
) -> Function:
|
|
260
|
+
"""Reference a Function from a deployed App by its name.
|
|
261
|
+
|
|
262
|
+
This is a lazy method that defers hydrating the local
|
|
263
|
+
object with metadata from Modal servers until the first
|
|
264
|
+
time it is actually used.
|
|
265
|
+
|
|
266
|
+
```python
|
|
267
|
+
f = modal.Function.from_name("other-app", "function")
|
|
268
|
+
```
|
|
269
|
+
"""
|
|
270
|
+
...
|
|
169
271
|
|
|
170
272
|
@property
|
|
171
|
-
def tag(self) -> str:
|
|
273
|
+
def tag(self) -> str:
|
|
274
|
+
"""mdmd:hidden"""
|
|
275
|
+
...
|
|
276
|
+
|
|
172
277
|
@property
|
|
173
|
-
def app(self) -> modal.app.App:
|
|
278
|
+
def app(self) -> modal.app.App:
|
|
279
|
+
"""mdmd:hidden"""
|
|
280
|
+
...
|
|
281
|
+
|
|
174
282
|
@property
|
|
175
|
-
def stub(self) -> modal.app.App:
|
|
283
|
+
def stub(self) -> modal.app.App:
|
|
284
|
+
"""mdmd:hidden"""
|
|
285
|
+
...
|
|
286
|
+
|
|
176
287
|
@property
|
|
177
|
-
def info(self) -> modal._utils.function_utils.FunctionInfo:
|
|
288
|
+
def info(self) -> modal._utils.function_utils.FunctionInfo:
|
|
289
|
+
"""mdmd:hidden"""
|
|
290
|
+
...
|
|
291
|
+
|
|
178
292
|
@property
|
|
179
|
-
def spec(self) -> modal._functions._FunctionSpec:
|
|
293
|
+
def spec(self) -> modal._functions._FunctionSpec:
|
|
294
|
+
"""mdmd:hidden"""
|
|
295
|
+
...
|
|
296
|
+
|
|
180
297
|
def _is_web_endpoint(self) -> bool: ...
|
|
181
|
-
def get_build_def(self) -> str:
|
|
298
|
+
def get_build_def(self) -> str:
|
|
299
|
+
"""mdmd:hidden"""
|
|
300
|
+
...
|
|
301
|
+
|
|
182
302
|
def _initialize_from_empty(self): ...
|
|
183
303
|
def _hydrate_metadata(self, metadata: typing.Optional[google.protobuf.message.Message]): ...
|
|
184
304
|
def _get_metadata(self): ...
|
|
185
305
|
def _check_no_web_url(self, fn_name: str): ...
|
|
186
306
|
@property
|
|
187
|
-
def web_url(self) -> typing.Optional[str]:
|
|
307
|
+
def web_url(self) -> typing.Optional[str]:
|
|
308
|
+
"""mdmd:hidden
|
|
309
|
+
Deprecated. Use the `Function.get_web_url()` method instead.
|
|
310
|
+
|
|
311
|
+
URL of a Function running as a web endpoint.
|
|
312
|
+
"""
|
|
313
|
+
...
|
|
188
314
|
|
|
189
315
|
class __get_web_url_spec(typing_extensions.Protocol[SUPERSELF]):
|
|
190
|
-
def __call__(self, /) -> typing.Optional[str]:
|
|
191
|
-
|
|
316
|
+
def __call__(self, /) -> typing.Optional[str]:
|
|
317
|
+
"""URL of a Function running as a web endpoint."""
|
|
318
|
+
...
|
|
319
|
+
|
|
320
|
+
async def aio(self, /) -> typing.Optional[str]:
|
|
321
|
+
"""URL of a Function running as a web endpoint."""
|
|
322
|
+
...
|
|
192
323
|
|
|
193
324
|
get_web_url: __get_web_url_spec[typing_extensions.Self]
|
|
194
325
|
|
|
326
|
+
class ___experimental_get_flash_urls_spec(typing_extensions.Protocol[SUPERSELF]):
|
|
327
|
+
def __call__(self, /) -> typing.Optional[list[str]]:
|
|
328
|
+
"""URL of the flash service for the function."""
|
|
329
|
+
...
|
|
330
|
+
|
|
331
|
+
async def aio(self, /) -> typing.Optional[list[str]]:
|
|
332
|
+
"""URL of the flash service for the function."""
|
|
333
|
+
...
|
|
334
|
+
|
|
335
|
+
_experimental_get_flash_urls: ___experimental_get_flash_urls_spec[typing_extensions.Self]
|
|
336
|
+
|
|
195
337
|
@property
|
|
196
|
-
def is_generator(self) -> bool:
|
|
338
|
+
def is_generator(self) -> bool:
|
|
339
|
+
"""mdmd:hidden"""
|
|
340
|
+
...
|
|
197
341
|
|
|
198
342
|
class ___map_spec(typing_extensions.Protocol[SUPERSELF]):
|
|
199
343
|
def __call__(
|
|
200
|
-
self,
|
|
201
|
-
|
|
344
|
+
self,
|
|
345
|
+
/,
|
|
346
|
+
input_queue: modal.parallel_map.SynchronizedQueue,
|
|
347
|
+
order_outputs: bool,
|
|
348
|
+
return_exceptions: bool,
|
|
349
|
+
wrap_returned_exceptions: bool,
|
|
350
|
+
) -> typing.Generator[typing.Any, None, None]:
|
|
351
|
+
"""mdmd:hidden
|
|
352
|
+
|
|
353
|
+
Synchronicity-wrapped map implementation. To be safe against invocations of user code in
|
|
354
|
+
the synchronicity thread it doesn't accept an [async]iterator, and instead takes a
|
|
355
|
+
_SynchronizedQueue instance that is fed by higher level functions like .map()
|
|
356
|
+
|
|
357
|
+
_SynchronizedQueue is used instead of asyncio.Queue so that the main thread can put
|
|
358
|
+
items in the queue safely.
|
|
359
|
+
"""
|
|
360
|
+
...
|
|
361
|
+
|
|
202
362
|
def aio(
|
|
203
|
-
self,
|
|
204
|
-
|
|
363
|
+
self,
|
|
364
|
+
/,
|
|
365
|
+
input_queue: modal.parallel_map.SynchronizedQueue,
|
|
366
|
+
order_outputs: bool,
|
|
367
|
+
return_exceptions: bool,
|
|
368
|
+
wrap_returned_exceptions: bool,
|
|
369
|
+
) -> collections.abc.AsyncGenerator[typing.Any, None]:
|
|
370
|
+
"""mdmd:hidden
|
|
371
|
+
|
|
372
|
+
Synchronicity-wrapped map implementation. To be safe against invocations of user code in
|
|
373
|
+
the synchronicity thread it doesn't accept an [async]iterator, and instead takes a
|
|
374
|
+
_SynchronizedQueue instance that is fed by higher level functions like .map()
|
|
375
|
+
|
|
376
|
+
_SynchronizedQueue is used instead of asyncio.Queue so that the main thread can put
|
|
377
|
+
items in the queue safely.
|
|
378
|
+
"""
|
|
379
|
+
...
|
|
205
380
|
|
|
206
381
|
_map: ___map_spec[typing_extensions.Self]
|
|
207
382
|
|
|
383
|
+
class ___spawn_map_spec(typing_extensions.Protocol[ReturnType_INNER, SUPERSELF]):
|
|
384
|
+
def __call__(self, /, input_queue: modal.parallel_map.SynchronizedQueue) -> FunctionCall[ReturnType_INNER]: ...
|
|
385
|
+
async def aio(self, /, input_queue: modal.parallel_map.SynchronizedQueue) -> FunctionCall[ReturnType_INNER]: ...
|
|
386
|
+
|
|
387
|
+
_spawn_map: ___spawn_map_spec[modal._functions.ReturnType, typing_extensions.Self]
|
|
388
|
+
|
|
208
389
|
class ___call_function_spec(typing_extensions.Protocol[ReturnType_INNER, SUPERSELF]):
|
|
209
390
|
def __call__(self, /, args, kwargs) -> ReturnType_INNER: ...
|
|
210
391
|
async def aio(self, /, args, kwargs) -> ReturnType_INNER: ...
|
|
@@ -227,15 +408,25 @@ class Function(
|
|
|
227
408
|
|
|
228
409
|
_call_generator: ___call_generator_spec[typing_extensions.Self]
|
|
229
410
|
|
|
230
|
-
class __remote_spec(typing_extensions.Protocol[
|
|
231
|
-
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> ReturnType_INNER:
|
|
232
|
-
|
|
411
|
+
class __remote_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER, SUPERSELF]):
|
|
412
|
+
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> ReturnType_INNER:
|
|
413
|
+
"""Calls the function remotely, executing it with the given arguments and returning the execution's result."""
|
|
414
|
+
...
|
|
415
|
+
|
|
416
|
+
async def aio(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> ReturnType_INNER:
|
|
417
|
+
"""Calls the function remotely, executing it with the given arguments and returning the execution's result."""
|
|
418
|
+
...
|
|
233
419
|
|
|
234
|
-
remote: __remote_spec[modal._functions.
|
|
420
|
+
remote: __remote_spec[modal._functions.P, modal._functions.ReturnType, typing_extensions.Self]
|
|
235
421
|
|
|
236
422
|
class __remote_gen_spec(typing_extensions.Protocol[SUPERSELF]):
|
|
237
|
-
def __call__(self, /, *args, **kwargs) -> typing.Generator[typing.Any, None, None]:
|
|
238
|
-
|
|
423
|
+
def __call__(self, /, *args, **kwargs) -> typing.Generator[typing.Any, None, None]:
|
|
424
|
+
"""Calls the generator remotely, executing it with the given arguments and returning the execution's result."""
|
|
425
|
+
...
|
|
426
|
+
|
|
427
|
+
def aio(self, /, *args, **kwargs) -> collections.abc.AsyncGenerator[typing.Any, None]:
|
|
428
|
+
"""Calls the generator remotely, executing it with the given arguments and returning the execution's result."""
|
|
429
|
+
...
|
|
239
430
|
|
|
240
431
|
remote_gen: __remote_gen_spec[typing_extensions.Self]
|
|
241
432
|
|
|
@@ -244,14 +435,40 @@ class Function(
|
|
|
244
435
|
def _get_obj(self) -> typing.Optional[modal.cls.Obj]: ...
|
|
245
436
|
def local(
|
|
246
437
|
self, *args: modal._functions.P.args, **kwargs: modal._functions.P.kwargs
|
|
247
|
-
) -> modal._functions.OriginalReturnType:
|
|
438
|
+
) -> modal._functions.OriginalReturnType:
|
|
439
|
+
"""Calls the function locally, executing it with the given arguments and returning the execution's result.
|
|
440
|
+
|
|
441
|
+
The function will execute in the same environment as the caller, just like calling the underlying function
|
|
442
|
+
directly in Python. In particular, only secrets available in the caller environment will be available
|
|
443
|
+
through environment variables.
|
|
444
|
+
"""
|
|
445
|
+
...
|
|
248
446
|
|
|
249
|
-
class ___experimental_spawn_spec(typing_extensions.Protocol[
|
|
250
|
-
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
|
|
251
|
-
|
|
447
|
+
class ___experimental_spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER, SUPERSELF]):
|
|
448
|
+
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
|
|
449
|
+
"""[Experimental] Calls the function with the given arguments, without waiting for the results.
|
|
450
|
+
|
|
451
|
+
This experimental version of the spawn method allows up to 1 million inputs to be spawned.
|
|
452
|
+
|
|
453
|
+
Returns a `modal.FunctionCall` object, that can later be polled or
|
|
454
|
+
waited for using `.get(timeout=...)`.
|
|
455
|
+
Conceptually similar to `multiprocessing.pool.apply_async`, or a Future/Promise in other contexts.
|
|
456
|
+
"""
|
|
457
|
+
...
|
|
458
|
+
|
|
459
|
+
async def aio(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
|
|
460
|
+
"""[Experimental] Calls the function with the given arguments, without waiting for the results.
|
|
461
|
+
|
|
462
|
+
This experimental version of the spawn method allows up to 1 million inputs to be spawned.
|
|
463
|
+
|
|
464
|
+
Returns a `modal.FunctionCall` object, that can later be polled or
|
|
465
|
+
waited for using `.get(timeout=...)`.
|
|
466
|
+
Conceptually similar to `multiprocessing.pool.apply_async`, or a Future/Promise in other contexts.
|
|
467
|
+
"""
|
|
468
|
+
...
|
|
252
469
|
|
|
253
470
|
_experimental_spawn: ___experimental_spawn_spec[
|
|
254
|
-
modal._functions.
|
|
471
|
+
modal._functions.P, modal._functions.ReturnType, typing_extensions.Self
|
|
255
472
|
]
|
|
256
473
|
|
|
257
474
|
class ___spawn_map_inner_spec(typing_extensions.Protocol[P_INNER, SUPERSELF]):
|
|
@@ -260,30 +477,103 @@ class Function(
|
|
|
260
477
|
|
|
261
478
|
_spawn_map_inner: ___spawn_map_inner_spec[modal._functions.P, typing_extensions.Self]
|
|
262
479
|
|
|
263
|
-
class __spawn_spec(typing_extensions.Protocol[
|
|
264
|
-
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
|
|
265
|
-
|
|
480
|
+
class __spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER, SUPERSELF]):
|
|
481
|
+
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
|
|
482
|
+
"""Calls the function with the given arguments, without waiting for the results.
|
|
266
483
|
|
|
267
|
-
|
|
484
|
+
Returns a [`modal.FunctionCall`](https://modal.com/docs/reference/modal.FunctionCall) object
|
|
485
|
+
that can later be polled or waited for using
|
|
486
|
+
[`.get(timeout=...)`](https://modal.com/docs/reference/modal.FunctionCall#get).
|
|
487
|
+
Conceptually similar to `multiprocessing.pool.apply_async`, or a Future/Promise in other contexts.
|
|
488
|
+
"""
|
|
489
|
+
...
|
|
268
490
|
|
|
269
|
-
|
|
491
|
+
async def aio(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
|
|
492
|
+
"""Calls the function with the given arguments, without waiting for the results.
|
|
493
|
+
|
|
494
|
+
Returns a [`modal.FunctionCall`](https://modal.com/docs/reference/modal.FunctionCall) object
|
|
495
|
+
that can later be polled or waited for using
|
|
496
|
+
[`.get(timeout=...)`](https://modal.com/docs/reference/modal.FunctionCall#get).
|
|
497
|
+
Conceptually similar to `multiprocessing.pool.apply_async`, or a Future/Promise in other contexts.
|
|
498
|
+
"""
|
|
499
|
+
...
|
|
500
|
+
|
|
501
|
+
spawn: __spawn_spec[modal._functions.P, modal._functions.ReturnType, typing_extensions.Self]
|
|
502
|
+
|
|
503
|
+
def get_raw_f(self) -> collections.abc.Callable[..., typing.Any]:
|
|
504
|
+
"""Return the inner Python object wrapped by this Modal Function."""
|
|
505
|
+
...
|
|
270
506
|
|
|
271
507
|
class __get_current_stats_spec(typing_extensions.Protocol[SUPERSELF]):
|
|
272
|
-
def __call__(self, /) -> modal._functions.FunctionStats:
|
|
273
|
-
|
|
508
|
+
def __call__(self, /) -> modal._functions.FunctionStats:
|
|
509
|
+
"""Return a `FunctionStats` object describing the current function's queue and runner counts."""
|
|
510
|
+
...
|
|
511
|
+
|
|
512
|
+
async def aio(self, /) -> modal._functions.FunctionStats:
|
|
513
|
+
"""Return a `FunctionStats` object describing the current function's queue and runner counts."""
|
|
514
|
+
...
|
|
274
515
|
|
|
275
516
|
get_current_stats: __get_current_stats_spec[typing_extensions.Self]
|
|
276
517
|
|
|
277
518
|
class ___get_schema_spec(typing_extensions.Protocol[SUPERSELF]):
|
|
278
|
-
def __call__(self, /) -> modal_proto.api_pb2.FunctionSchema:
|
|
279
|
-
|
|
519
|
+
def __call__(self, /) -> modal_proto.api_pb2.FunctionSchema:
|
|
520
|
+
"""Returns recorded schema for function, internal use only for now"""
|
|
521
|
+
...
|
|
522
|
+
|
|
523
|
+
async def aio(self, /) -> modal_proto.api_pb2.FunctionSchema:
|
|
524
|
+
"""Returns recorded schema for function, internal use only for now"""
|
|
525
|
+
...
|
|
280
526
|
|
|
281
527
|
_get_schema: ___get_schema_spec[typing_extensions.Self]
|
|
282
528
|
|
|
283
529
|
class __map_spec(typing_extensions.Protocol[SUPERSELF]):
|
|
284
530
|
def __call__(
|
|
285
|
-
self,
|
|
286
|
-
|
|
531
|
+
self,
|
|
532
|
+
/,
|
|
533
|
+
*input_iterators,
|
|
534
|
+
kwargs={},
|
|
535
|
+
order_outputs: bool = True,
|
|
536
|
+
return_exceptions: bool = False,
|
|
537
|
+
wrap_returned_exceptions: bool = True,
|
|
538
|
+
) -> modal._utils.async_utils.AsyncOrSyncIterable:
|
|
539
|
+
"""Parallel map over a set of inputs.
|
|
540
|
+
|
|
541
|
+
Takes one iterator argument per argument in the function being mapped over.
|
|
542
|
+
|
|
543
|
+
Example:
|
|
544
|
+
```python
|
|
545
|
+
@app.function()
|
|
546
|
+
def my_func(a):
|
|
547
|
+
return a ** 2
|
|
548
|
+
|
|
549
|
+
|
|
550
|
+
@app.local_entrypoint()
|
|
551
|
+
def main():
|
|
552
|
+
assert list(my_func.map([1, 2, 3, 4])) == [1, 4, 9, 16]
|
|
553
|
+
```
|
|
554
|
+
|
|
555
|
+
If applied to a `app.function`, `map()` returns one result per input and the output order
|
|
556
|
+
is guaranteed to be the same as the input order. Set `order_outputs=False` to return results
|
|
557
|
+
in the order that they are completed instead.
|
|
558
|
+
|
|
559
|
+
`return_exceptions` can be used to treat exceptions as successful results:
|
|
560
|
+
|
|
561
|
+
```python
|
|
562
|
+
@app.function()
|
|
563
|
+
def my_func(a):
|
|
564
|
+
if a == 2:
|
|
565
|
+
raise Exception("ohno")
|
|
566
|
+
return a ** 2
|
|
567
|
+
|
|
568
|
+
|
|
569
|
+
@app.local_entrypoint()
|
|
570
|
+
def main():
|
|
571
|
+
# [0, 1, UserCodeException(Exception('ohno'))]
|
|
572
|
+
print(list(my_func.map(range(3), return_exceptions=True)))
|
|
573
|
+
```
|
|
574
|
+
"""
|
|
575
|
+
...
|
|
576
|
+
|
|
287
577
|
def aio(
|
|
288
578
|
self,
|
|
289
579
|
/,
|
|
@@ -291,6 +581,7 @@ class Function(
|
|
|
291
581
|
kwargs={},
|
|
292
582
|
order_outputs: bool = True,
|
|
293
583
|
return_exceptions: bool = False,
|
|
584
|
+
wrap_returned_exceptions: bool = True,
|
|
294
585
|
) -> typing.AsyncGenerator[typing.Any, None]: ...
|
|
295
586
|
|
|
296
587
|
map: __map_spec[typing_extensions.Self]
|
|
@@ -304,7 +595,26 @@ class Function(
|
|
|
304
595
|
kwargs={},
|
|
305
596
|
order_outputs: bool = True,
|
|
306
597
|
return_exceptions: bool = False,
|
|
307
|
-
|
|
598
|
+
wrap_returned_exceptions: bool = True,
|
|
599
|
+
) -> modal._utils.async_utils.AsyncOrSyncIterable:
|
|
600
|
+
"""Like `map`, but spreads arguments over multiple function arguments.
|
|
601
|
+
|
|
602
|
+
Assumes every input is a sequence (e.g. a tuple).
|
|
603
|
+
|
|
604
|
+
Example:
|
|
605
|
+
```python
|
|
606
|
+
@app.function()
|
|
607
|
+
def my_func(a, b):
|
|
608
|
+
return a + b
|
|
609
|
+
|
|
610
|
+
|
|
611
|
+
@app.local_entrypoint()
|
|
612
|
+
def main():
|
|
613
|
+
assert list(my_func.starmap([(1, 2), (3, 4)])) == [3, 7]
|
|
614
|
+
```
|
|
615
|
+
"""
|
|
616
|
+
...
|
|
617
|
+
|
|
308
618
|
def aio(
|
|
309
619
|
self,
|
|
310
620
|
/,
|
|
@@ -315,68 +625,339 @@ class Function(
|
|
|
315
625
|
kwargs={},
|
|
316
626
|
order_outputs: bool = True,
|
|
317
627
|
return_exceptions: bool = False,
|
|
628
|
+
wrap_returned_exceptions: bool = True,
|
|
318
629
|
) -> typing.AsyncIterable[typing.Any]: ...
|
|
319
630
|
|
|
320
631
|
starmap: __starmap_spec[typing_extensions.Self]
|
|
321
632
|
|
|
322
633
|
class __for_each_spec(typing_extensions.Protocol[SUPERSELF]):
|
|
323
|
-
def __call__(self, /, *input_iterators, kwargs={}, ignore_exceptions: bool = False):
|
|
634
|
+
def __call__(self, /, *input_iterators, kwargs={}, ignore_exceptions: bool = False):
|
|
635
|
+
"""Execute function for all inputs, ignoring outputs. Waits for completion of the inputs.
|
|
636
|
+
|
|
637
|
+
Convenient alias for `.map()` in cases where the function just needs to be called.
|
|
638
|
+
as the caller doesn't have to consume the generator to process the inputs.
|
|
639
|
+
"""
|
|
640
|
+
...
|
|
641
|
+
|
|
324
642
|
async def aio(self, /, *input_iterators, kwargs={}, ignore_exceptions: bool = False) -> None: ...
|
|
325
643
|
|
|
326
644
|
for_each: __for_each_spec[typing_extensions.Self]
|
|
327
645
|
|
|
328
646
|
class __spawn_map_spec(typing_extensions.Protocol[SUPERSELF]):
|
|
329
|
-
def __call__(self, /, *input_iterators, kwargs={}) -> None:
|
|
330
|
-
|
|
647
|
+
def __call__(self, /, *input_iterators, kwargs={}) -> None:
|
|
648
|
+
"""Spawn parallel execution over a set of inputs, exiting as soon as the inputs are created (without waiting
|
|
649
|
+
for the map to complete).
|
|
650
|
+
|
|
651
|
+
Takes one iterator argument per argument in the function being mapped over.
|
|
652
|
+
|
|
653
|
+
Example:
|
|
654
|
+
```python
|
|
655
|
+
@app.function()
|
|
656
|
+
def my_func(a):
|
|
657
|
+
return a ** 2
|
|
658
|
+
|
|
659
|
+
|
|
660
|
+
@app.local_entrypoint()
|
|
661
|
+
def main():
|
|
662
|
+
my_func.spawn_map([1, 2, 3, 4])
|
|
663
|
+
```
|
|
664
|
+
|
|
665
|
+
Programmatic retrieval of results will be supported in a future update.
|
|
666
|
+
"""
|
|
667
|
+
...
|
|
668
|
+
|
|
669
|
+
async def aio(self, /, *input_iterators, kwargs={}) -> None:
|
|
670
|
+
"""This runs in an event loop on the main thread. It consumes inputs from the input iterators and creates async
|
|
671
|
+
function calls for each.
|
|
672
|
+
"""
|
|
673
|
+
...
|
|
331
674
|
|
|
332
675
|
spawn_map: __spawn_map_spec[typing_extensions.Self]
|
|
333
676
|
|
|
677
|
+
class __experimental_spawn_map_spec(typing_extensions.Protocol[SUPERSELF]):
|
|
678
|
+
def __call__(self, /, *input_iterators, kwargs={}) -> modal._functions._FunctionCall:
|
|
679
|
+
"""mdmd:hidden
|
|
680
|
+
Spawn parallel execution over a set of inputs, returning as soon as the inputs are created.
|
|
681
|
+
|
|
682
|
+
Unlike `modal.Function.map`, this method does not block on completion of the remote execution but
|
|
683
|
+
returns a `modal.FunctionCall` object that can be used to poll status and retrieve results later.
|
|
684
|
+
|
|
685
|
+
Takes one iterator argument per argument in the function being mapped over.
|
|
686
|
+
|
|
687
|
+
Example:
|
|
688
|
+
```python
|
|
689
|
+
@app.function()
|
|
690
|
+
def my_func(a, b):
|
|
691
|
+
return a ** b
|
|
692
|
+
|
|
693
|
+
|
|
694
|
+
@app.local_entrypoint()
|
|
695
|
+
def main():
|
|
696
|
+
fc = my_func.spawn_map([1, 2], [3, 4])
|
|
697
|
+
```
|
|
698
|
+
"""
|
|
699
|
+
...
|
|
700
|
+
|
|
701
|
+
async def aio(self, /, *input_iterators, kwargs={}) -> modal._functions._FunctionCall: ...
|
|
702
|
+
|
|
703
|
+
experimental_spawn_map: __experimental_spawn_map_spec[typing_extensions.Self]
|
|
704
|
+
|
|
334
705
|
class FunctionCall(typing.Generic[modal._functions.ReturnType], modal.object.Object):
|
|
706
|
+
"""A reference to an executed function call.
|
|
707
|
+
|
|
708
|
+
Constructed using `.spawn(...)` on a Modal function with the same
|
|
709
|
+
arguments that a function normally takes. Acts as a reference to
|
|
710
|
+
an ongoing function call that can be passed around and used to
|
|
711
|
+
poll or fetch function results at some later time.
|
|
712
|
+
|
|
713
|
+
Conceptually similar to a Future/Promise/AsyncResult in other contexts and languages.
|
|
714
|
+
"""
|
|
715
|
+
|
|
335
716
|
_is_generator: bool
|
|
717
|
+
_num_inputs: typing.Optional[int]
|
|
718
|
+
|
|
719
|
+
def __init__(self, *args, **kwargs):
|
|
720
|
+
"""mdmd:hidden"""
|
|
721
|
+
...
|
|
336
722
|
|
|
337
|
-
def __init__(self, *args, **kwargs): ...
|
|
338
723
|
def _invocation(self): ...
|
|
339
724
|
|
|
725
|
+
class __num_inputs_spec(typing_extensions.Protocol[SUPERSELF]):
|
|
726
|
+
def __call__(self, /) -> int:
|
|
727
|
+
"""Get the number of inputs in the function call."""
|
|
728
|
+
...
|
|
729
|
+
|
|
730
|
+
async def aio(self, /) -> int:
|
|
731
|
+
"""Get the number of inputs in the function call."""
|
|
732
|
+
...
|
|
733
|
+
|
|
734
|
+
num_inputs: __num_inputs_spec[typing_extensions.Self]
|
|
735
|
+
|
|
340
736
|
class __get_spec(typing_extensions.Protocol[ReturnType_INNER, SUPERSELF]):
|
|
341
|
-
def __call__(self, /, timeout: typing.Optional[float] = None) -> ReturnType_INNER:
|
|
342
|
-
|
|
737
|
+
def __call__(self, /, timeout: typing.Optional[float] = None, *, index: int = 0) -> ReturnType_INNER:
|
|
738
|
+
"""Get the result of the index-th input of the function call.
|
|
739
|
+
`.spawn()` calls have a single output, so only specifying `index=0` is valid.
|
|
740
|
+
A non-zero index is useful when your function has multiple outputs, like via `.spawn_map()`.
|
|
741
|
+
|
|
742
|
+
This function waits indefinitely by default. It takes an optional
|
|
743
|
+
`timeout` argument that specifies the maximum number of seconds to wait,
|
|
744
|
+
which can be set to `0` to poll for an output immediately.
|
|
745
|
+
|
|
746
|
+
The returned coroutine is not cancellation-safe.
|
|
747
|
+
"""
|
|
748
|
+
...
|
|
749
|
+
|
|
750
|
+
async def aio(self, /, timeout: typing.Optional[float] = None, *, index: int = 0) -> ReturnType_INNER:
|
|
751
|
+
"""Get the result of the index-th input of the function call.
|
|
752
|
+
`.spawn()` calls have a single output, so only specifying `index=0` is valid.
|
|
753
|
+
A non-zero index is useful when your function has multiple outputs, like via `.spawn_map()`.
|
|
754
|
+
|
|
755
|
+
This function waits indefinitely by default. It takes an optional
|
|
756
|
+
`timeout` argument that specifies the maximum number of seconds to wait,
|
|
757
|
+
which can be set to `0` to poll for an output immediately.
|
|
758
|
+
|
|
759
|
+
The returned coroutine is not cancellation-safe.
|
|
760
|
+
"""
|
|
761
|
+
...
|
|
343
762
|
|
|
344
763
|
get: __get_spec[modal._functions.ReturnType, typing_extensions.Self]
|
|
345
764
|
|
|
765
|
+
class __iter_spec(typing_extensions.Protocol[ReturnType_INNER, SUPERSELF]):
|
|
766
|
+
def __call__(self, /, *, start: int = 0, end: typing.Optional[int] = None) -> typing.Iterator[ReturnType_INNER]:
|
|
767
|
+
"""Iterate in-order over the results of the function call.
|
|
768
|
+
|
|
769
|
+
Optionally, specify a range [start, end) to iterate over.
|
|
770
|
+
|
|
771
|
+
Example:
|
|
772
|
+
```python
|
|
773
|
+
@app.function()
|
|
774
|
+
def my_func(a):
|
|
775
|
+
return a ** 2
|
|
776
|
+
|
|
777
|
+
|
|
778
|
+
@app.local_entrypoint()
|
|
779
|
+
def main():
|
|
780
|
+
fc = my_func.spawn_map([1, 2, 3, 4])
|
|
781
|
+
assert list(fc.iter()) == [1, 4, 9, 16]
|
|
782
|
+
assert list(fc.iter(start=1, end=3)) == [4, 9]
|
|
783
|
+
```
|
|
784
|
+
|
|
785
|
+
If `end` is not provided, it will iterate over all results.
|
|
786
|
+
"""
|
|
787
|
+
...
|
|
788
|
+
|
|
789
|
+
def aio(self, /, *, start: int = 0, end: typing.Optional[int] = None) -> typing.AsyncIterator[ReturnType_INNER]:
|
|
790
|
+
"""Iterate in-order over the results of the function call.
|
|
791
|
+
|
|
792
|
+
Optionally, specify a range [start, end) to iterate over.
|
|
793
|
+
|
|
794
|
+
Example:
|
|
795
|
+
```python
|
|
796
|
+
@app.function()
|
|
797
|
+
def my_func(a):
|
|
798
|
+
return a ** 2
|
|
799
|
+
|
|
800
|
+
|
|
801
|
+
@app.local_entrypoint()
|
|
802
|
+
def main():
|
|
803
|
+
fc = my_func.spawn_map([1, 2, 3, 4])
|
|
804
|
+
assert list(fc.iter()) == [1, 4, 9, 16]
|
|
805
|
+
assert list(fc.iter(start=1, end=3)) == [4, 9]
|
|
806
|
+
```
|
|
807
|
+
|
|
808
|
+
If `end` is not provided, it will iterate over all results.
|
|
809
|
+
"""
|
|
810
|
+
...
|
|
811
|
+
|
|
812
|
+
iter: __iter_spec[modal._functions.ReturnType, typing_extensions.Self]
|
|
813
|
+
|
|
346
814
|
class __get_call_graph_spec(typing_extensions.Protocol[SUPERSELF]):
|
|
347
|
-
def __call__(self, /) -> list[modal.call_graph.InputInfo]:
|
|
348
|
-
|
|
815
|
+
def __call__(self, /) -> list[modal.call_graph.InputInfo]:
|
|
816
|
+
"""Returns a structure representing the call graph from a given root
|
|
817
|
+
call ID, along with the status of execution for each node.
|
|
818
|
+
|
|
819
|
+
See [`modal.call_graph`](https://modal.com/docs/reference/modal.call_graph) reference page
|
|
820
|
+
for documentation on the structure of the returned `InputInfo` items.
|
|
821
|
+
"""
|
|
822
|
+
...
|
|
823
|
+
|
|
824
|
+
async def aio(self, /) -> list[modal.call_graph.InputInfo]:
|
|
825
|
+
"""Returns a structure representing the call graph from a given root
|
|
826
|
+
call ID, along with the status of execution for each node.
|
|
827
|
+
|
|
828
|
+
See [`modal.call_graph`](https://modal.com/docs/reference/modal.call_graph) reference page
|
|
829
|
+
for documentation on the structure of the returned `InputInfo` items.
|
|
830
|
+
"""
|
|
831
|
+
...
|
|
349
832
|
|
|
350
833
|
get_call_graph: __get_call_graph_spec[typing_extensions.Self]
|
|
351
834
|
|
|
352
835
|
class __cancel_spec(typing_extensions.Protocol[SUPERSELF]):
|
|
353
|
-
def __call__(self, /, terminate_containers: bool = False):
|
|
354
|
-
|
|
836
|
+
def __call__(self, /, terminate_containers: bool = False):
|
|
837
|
+
"""Cancels the function call, which will stop its execution and mark its inputs as
|
|
838
|
+
[`TERMINATED`](https://modal.com/docs/reference/modal.call_graph#modalcall_graphinputstatus).
|
|
839
|
+
|
|
840
|
+
If `terminate_containers=True` - the containers running the cancelled inputs are all terminated
|
|
841
|
+
causing any non-cancelled inputs on those containers to be rescheduled in new containers.
|
|
842
|
+
"""
|
|
843
|
+
...
|
|
844
|
+
|
|
845
|
+
async def aio(self, /, terminate_containers: bool = False):
|
|
846
|
+
"""Cancels the function call, which will stop its execution and mark its inputs as
|
|
847
|
+
[`TERMINATED`](https://modal.com/docs/reference/modal.call_graph#modalcall_graphinputstatus).
|
|
848
|
+
|
|
849
|
+
If `terminate_containers=True` - the containers running the cancelled inputs are all terminated
|
|
850
|
+
causing any non-cancelled inputs on those containers to be rescheduled in new containers.
|
|
851
|
+
"""
|
|
852
|
+
...
|
|
355
853
|
|
|
356
854
|
cancel: __cancel_spec[typing_extensions.Self]
|
|
357
855
|
|
|
358
856
|
class __from_id_spec(typing_extensions.Protocol):
|
|
359
857
|
def __call__(
|
|
360
858
|
self, /, function_call_id: str, client: typing.Optional[modal.client.Client] = None
|
|
361
|
-
) -> FunctionCall[typing.Any]:
|
|
859
|
+
) -> FunctionCall[typing.Any]:
|
|
860
|
+
"""Instantiate a FunctionCall object from an existing ID.
|
|
861
|
+
|
|
862
|
+
Examples:
|
|
863
|
+
|
|
864
|
+
```python notest
|
|
865
|
+
# Spawn a FunctionCall and keep track of its object ID
|
|
866
|
+
fc = my_func.spawn()
|
|
867
|
+
fc_id = fc.object_id
|
|
868
|
+
|
|
869
|
+
# Later, use the ID to re-instantiate the FunctionCall object
|
|
870
|
+
fc = _FunctionCall.from_id(fc_id)
|
|
871
|
+
result = fc.get()
|
|
872
|
+
```
|
|
873
|
+
|
|
874
|
+
Note that it's only necessary to re-instantiate the `FunctionCall` with this method
|
|
875
|
+
if you no longer have access to the original object returned from `Function.spawn`.
|
|
876
|
+
"""
|
|
877
|
+
...
|
|
878
|
+
|
|
362
879
|
async def aio(
|
|
363
880
|
self, /, function_call_id: str, client: typing.Optional[modal.client.Client] = None
|
|
364
|
-
) -> FunctionCall[typing.Any]:
|
|
881
|
+
) -> FunctionCall[typing.Any]:
|
|
882
|
+
"""Instantiate a FunctionCall object from an existing ID.
|
|
883
|
+
|
|
884
|
+
Examples:
|
|
885
|
+
|
|
886
|
+
```python notest
|
|
887
|
+
# Spawn a FunctionCall and keep track of its object ID
|
|
888
|
+
fc = my_func.spawn()
|
|
889
|
+
fc_id = fc.object_id
|
|
890
|
+
|
|
891
|
+
# Later, use the ID to re-instantiate the FunctionCall object
|
|
892
|
+
fc = _FunctionCall.from_id(fc_id)
|
|
893
|
+
result = fc.get()
|
|
894
|
+
```
|
|
895
|
+
|
|
896
|
+
Note that it's only necessary to re-instantiate the `FunctionCall` with this method
|
|
897
|
+
if you no longer have access to the original object returned from `Function.spawn`.
|
|
898
|
+
"""
|
|
899
|
+
...
|
|
365
900
|
|
|
366
901
|
from_id: __from_id_spec
|
|
367
902
|
|
|
368
903
|
class __gather_spec(typing_extensions.Protocol):
|
|
369
|
-
def __call__(
|
|
370
|
-
|
|
371
|
-
|
|
904
|
+
def __call__(self, /, *function_calls: FunctionCall[modal._functions.T]) -> typing.Sequence[modal._functions.T]:
|
|
905
|
+
"""Wait until all Modal FunctionCall objects have results before returning.
|
|
906
|
+
|
|
907
|
+
Accepts a variable number of `FunctionCall` objects, as returned by `Function.spawn()`.
|
|
908
|
+
|
|
909
|
+
Returns a list of results from each FunctionCall, or raises an exception
|
|
910
|
+
from the first failing function call.
|
|
911
|
+
|
|
912
|
+
Examples:
|
|
913
|
+
|
|
914
|
+
```python notest
|
|
915
|
+
fc1 = slow_func_1.spawn()
|
|
916
|
+
fc2 = slow_func_2.spawn()
|
|
917
|
+
|
|
918
|
+
result_1, result_2 = modal.FunctionCall.gather(fc1, fc2)
|
|
919
|
+
```
|
|
920
|
+
|
|
921
|
+
*Added in v0.73.69*: This method replaces the deprecated `modal.functions.gather` function.
|
|
922
|
+
"""
|
|
923
|
+
...
|
|
924
|
+
|
|
372
925
|
async def aio(
|
|
373
926
|
self, /, *function_calls: FunctionCall[modal._functions.T]
|
|
374
|
-
) -> typing.Sequence[modal._functions.T]:
|
|
927
|
+
) -> typing.Sequence[modal._functions.T]:
|
|
928
|
+
"""Wait until all Modal FunctionCall objects have results before returning.
|
|
929
|
+
|
|
930
|
+
Accepts a variable number of `FunctionCall` objects, as returned by `Function.spawn()`.
|
|
931
|
+
|
|
932
|
+
Returns a list of results from each FunctionCall, or raises an exception
|
|
933
|
+
from the first failing function call.
|
|
934
|
+
|
|
935
|
+
Examples:
|
|
936
|
+
|
|
937
|
+
```python notest
|
|
938
|
+
fc1 = slow_func_1.spawn()
|
|
939
|
+
fc2 = slow_func_2.spawn()
|
|
940
|
+
|
|
941
|
+
result_1, result_2 = modal.FunctionCall.gather(fc1, fc2)
|
|
942
|
+
```
|
|
943
|
+
|
|
944
|
+
*Added in v0.73.69*: This method replaces the deprecated `modal.functions.gather` function.
|
|
945
|
+
"""
|
|
946
|
+
...
|
|
375
947
|
|
|
376
948
|
gather: __gather_spec
|
|
377
949
|
|
|
378
950
|
class __gather_spec(typing_extensions.Protocol):
|
|
379
|
-
def __call__(self, /, *function_calls) -> typing.Sequence[modal._functions.T]:
|
|
380
|
-
|
|
951
|
+
def __call__(self, /, *function_calls) -> typing.Sequence[modal._functions.T]:
|
|
952
|
+
"""mdmd:hidden
|
|
953
|
+
Deprecated: Please use `modal.FunctionCall.gather()` instead.
|
|
954
|
+
"""
|
|
955
|
+
...
|
|
956
|
+
|
|
957
|
+
async def aio(self, /, *function_calls) -> typing.Sequence[modal._functions.T]:
|
|
958
|
+
"""mdmd:hidden
|
|
959
|
+
Deprecated: Please use `modal.FunctionCall.gather()` instead.
|
|
960
|
+
"""
|
|
961
|
+
...
|
|
381
962
|
|
|
382
963
|
gather: __gather_spec
|