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.

Files changed (160) hide show
  1. modal/__init__.py +0 -2
  2. modal/__main__.py +3 -4
  3. modal/_billing.py +80 -0
  4. modal/_clustered_functions.py +7 -3
  5. modal/_clustered_functions.pyi +15 -3
  6. modal/_container_entrypoint.py +51 -69
  7. modal/_functions.py +508 -240
  8. modal/_grpc_client.py +171 -0
  9. modal/_load_context.py +105 -0
  10. modal/_object.py +81 -21
  11. modal/_output.py +58 -45
  12. modal/_partial_function.py +48 -73
  13. modal/_pty.py +7 -3
  14. modal/_resolver.py +26 -46
  15. modal/_runtime/asgi.py +4 -3
  16. modal/_runtime/container_io_manager.py +358 -220
  17. modal/_runtime/container_io_manager.pyi +296 -101
  18. modal/_runtime/execution_context.py +18 -2
  19. modal/_runtime/execution_context.pyi +64 -7
  20. modal/_runtime/gpu_memory_snapshot.py +262 -57
  21. modal/_runtime/user_code_imports.py +28 -58
  22. modal/_serialization.py +90 -6
  23. modal/_traceback.py +42 -1
  24. modal/_tunnel.pyi +380 -12
  25. modal/_utils/async_utils.py +84 -29
  26. modal/_utils/auth_token_manager.py +111 -0
  27. modal/_utils/blob_utils.py +181 -58
  28. modal/_utils/deprecation.py +19 -0
  29. modal/_utils/function_utils.py +91 -47
  30. modal/_utils/grpc_utils.py +89 -66
  31. modal/_utils/mount_utils.py +26 -1
  32. modal/_utils/name_utils.py +17 -3
  33. modal/_utils/task_command_router_client.py +536 -0
  34. modal/_utils/time_utils.py +34 -6
  35. modal/app.py +256 -88
  36. modal/app.pyi +909 -92
  37. modal/billing.py +5 -0
  38. modal/builder/2025.06.txt +18 -0
  39. modal/builder/PREVIEW.txt +18 -0
  40. modal/builder/base-images.json +58 -0
  41. modal/cli/_download.py +19 -3
  42. modal/cli/_traceback.py +3 -2
  43. modal/cli/app.py +4 -4
  44. modal/cli/cluster.py +15 -7
  45. modal/cli/config.py +5 -3
  46. modal/cli/container.py +7 -6
  47. modal/cli/dict.py +22 -16
  48. modal/cli/entry_point.py +12 -5
  49. modal/cli/environment.py +5 -4
  50. modal/cli/import_refs.py +3 -3
  51. modal/cli/launch.py +102 -5
  52. modal/cli/network_file_system.py +11 -12
  53. modal/cli/profile.py +3 -2
  54. modal/cli/programs/launch_instance_ssh.py +94 -0
  55. modal/cli/programs/run_jupyter.py +1 -1
  56. modal/cli/programs/run_marimo.py +95 -0
  57. modal/cli/programs/vscode.py +1 -1
  58. modal/cli/queues.py +57 -26
  59. modal/cli/run.py +91 -23
  60. modal/cli/secret.py +48 -22
  61. modal/cli/token.py +7 -8
  62. modal/cli/utils.py +4 -7
  63. modal/cli/volume.py +31 -25
  64. modal/client.py +15 -85
  65. modal/client.pyi +183 -62
  66. modal/cloud_bucket_mount.py +5 -3
  67. modal/cloud_bucket_mount.pyi +197 -5
  68. modal/cls.py +200 -126
  69. modal/cls.pyi +446 -68
  70. modal/config.py +29 -11
  71. modal/container_process.py +319 -19
  72. modal/container_process.pyi +190 -20
  73. modal/dict.py +290 -71
  74. modal/dict.pyi +835 -83
  75. modal/environments.py +15 -27
  76. modal/environments.pyi +46 -24
  77. modal/exception.py +14 -2
  78. modal/experimental/__init__.py +194 -40
  79. modal/experimental/flash.py +618 -0
  80. modal/experimental/flash.pyi +380 -0
  81. modal/experimental/ipython.py +11 -7
  82. modal/file_io.py +29 -36
  83. modal/file_io.pyi +251 -53
  84. modal/file_pattern_matcher.py +56 -16
  85. modal/functions.pyi +673 -92
  86. modal/gpu.py +1 -1
  87. modal/image.py +528 -176
  88. modal/image.pyi +1572 -145
  89. modal/io_streams.py +458 -128
  90. modal/io_streams.pyi +433 -52
  91. modal/mount.py +216 -151
  92. modal/mount.pyi +225 -78
  93. modal/network_file_system.py +45 -62
  94. modal/network_file_system.pyi +277 -56
  95. modal/object.pyi +93 -17
  96. modal/parallel_map.py +942 -129
  97. modal/parallel_map.pyi +294 -15
  98. modal/partial_function.py +0 -2
  99. modal/partial_function.pyi +234 -19
  100. modal/proxy.py +17 -8
  101. modal/proxy.pyi +36 -3
  102. modal/queue.py +270 -65
  103. modal/queue.pyi +817 -57
  104. modal/runner.py +115 -101
  105. modal/runner.pyi +205 -49
  106. modal/sandbox.py +512 -136
  107. modal/sandbox.pyi +845 -111
  108. modal/schedule.py +1 -1
  109. modal/secret.py +300 -70
  110. modal/secret.pyi +589 -34
  111. modal/serving.py +7 -11
  112. modal/serving.pyi +7 -8
  113. modal/snapshot.py +11 -8
  114. modal/snapshot.pyi +25 -4
  115. modal/token_flow.py +4 -4
  116. modal/token_flow.pyi +28 -8
  117. modal/volume.py +416 -158
  118. modal/volume.pyi +1117 -121
  119. {modal-1.0.3.dev10.dist-info → modal-1.2.3.dev7.dist-info}/METADATA +10 -9
  120. modal-1.2.3.dev7.dist-info/RECORD +195 -0
  121. modal_docs/mdmd/mdmd.py +17 -4
  122. modal_proto/api.proto +534 -79
  123. modal_proto/api_grpc.py +337 -1
  124. modal_proto/api_pb2.py +1522 -968
  125. modal_proto/api_pb2.pyi +1619 -134
  126. modal_proto/api_pb2_grpc.py +699 -4
  127. modal_proto/api_pb2_grpc.pyi +226 -14
  128. modal_proto/modal_api_grpc.py +175 -154
  129. modal_proto/sandbox_router.proto +145 -0
  130. modal_proto/sandbox_router_grpc.py +105 -0
  131. modal_proto/sandbox_router_pb2.py +149 -0
  132. modal_proto/sandbox_router_pb2.pyi +333 -0
  133. modal_proto/sandbox_router_pb2_grpc.py +203 -0
  134. modal_proto/sandbox_router_pb2_grpc.pyi +75 -0
  135. modal_proto/task_command_router.proto +144 -0
  136. modal_proto/task_command_router_grpc.py +105 -0
  137. modal_proto/task_command_router_pb2.py +149 -0
  138. modal_proto/task_command_router_pb2.pyi +333 -0
  139. modal_proto/task_command_router_pb2_grpc.py +203 -0
  140. modal_proto/task_command_router_pb2_grpc.pyi +75 -0
  141. modal_version/__init__.py +1 -1
  142. modal/requirements/PREVIEW.txt +0 -16
  143. modal/requirements/base-images.json +0 -26
  144. modal-1.0.3.dev10.dist-info/RECORD +0 -179
  145. modal_proto/modal_options_grpc.py +0 -3
  146. modal_proto/options.proto +0 -19
  147. modal_proto/options_grpc.py +0 -3
  148. modal_proto/options_pb2.py +0 -35
  149. modal_proto/options_pb2.pyi +0 -20
  150. modal_proto/options_pb2_grpc.py +0 -4
  151. modal_proto/options_pb2_grpc.pyi +0 -7
  152. /modal/{requirements → builder}/2023.12.312.txt +0 -0
  153. /modal/{requirements → builder}/2023.12.txt +0 -0
  154. /modal/{requirements → builder}/2024.04.txt +0 -0
  155. /modal/{requirements → builder}/2024.10.txt +0 -0
  156. /modal/{requirements → builder}/README.md +0 -0
  157. {modal-1.0.3.dev10.dist-info → modal-1.2.3.dev7.dist-info}/WHEEL +0 -0
  158. {modal-1.0.3.dev10.dist-info → modal-1.2.3.dev7.dist-info}/entry_points.txt +0 -0
  159. {modal-1.0.3.dev10.dist-info → modal-1.2.3.dev7.dist-info}/licenses/LICENSE +0 -0
  160. {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
- secrets: collections.abc.Sequence[modal.secret.Secret] = (),
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: typing.Optional[int] = None,
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: typing.Optional[bool] = None,
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
- _experimental_enable_gpu_snapshot: bool = False,
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
- async def aio(self, /, warm_pool_size: int) -> None: ...
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, namespace, environment_name: typing.Optional[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], app_name: str, name: str, *, namespace=1, environment_name: typing.Optional[str] = None
146
- ) -> Function: ...
147
-
148
- class __lookup_spec(typing_extensions.Protocol):
149
- def __call__(
150
- self,
151
- /,
152
- app_name: str,
153
- name: str,
154
- namespace=1,
155
- client: typing.Optional[modal.client.Client] = None,
156
- environment_name: typing.Optional[str] = None,
157
- ) -> Function: ...
158
- async def aio(
159
- self,
160
- /,
161
- app_name: str,
162
- name: str,
163
- namespace=1,
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
- async def aio(self, /) -> typing.Optional[str]: ...
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, /, input_queue: modal.parallel_map.SynchronizedQueue, order_outputs: bool, return_exceptions: bool
201
- ) -> typing.Generator[typing.Any, None, None]: ...
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, /, input_queue: modal.parallel_map.SynchronizedQueue, order_outputs: bool, return_exceptions: bool
204
- ) -> collections.abc.AsyncGenerator[typing.Any, None]: ...
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[ReturnType_INNER, P_INNER, SUPERSELF]):
231
- def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> ReturnType_INNER: ...
232
- async def aio(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> ReturnType_INNER: ...
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.ReturnType, modal._functions.P, typing_extensions.Self]
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
- def aio(self, /, *args, **kwargs) -> collections.abc.AsyncGenerator[typing.Any, None]: ...
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[ReturnType_INNER, P_INNER, SUPERSELF]):
250
- def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]: ...
251
- async def aio(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]: ...
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.ReturnType, modal._functions.P, typing_extensions.Self
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[ReturnType_INNER, P_INNER, SUPERSELF]):
264
- def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]: ...
265
- async def aio(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]: ...
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
- spawn: __spawn_spec[modal._functions.ReturnType, modal._functions.P, typing_extensions.Self]
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
- def get_raw_f(self) -> collections.abc.Callable[..., typing.Any]: ...
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
- async def aio(self, /) -> modal._functions.FunctionStats: ...
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
- async def aio(self, /) -> modal_proto.api_pb2.FunctionSchema: ...
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, /, *input_iterators, kwargs={}, order_outputs: bool = True, return_exceptions: bool = False
286
- ) -> modal._utils.async_utils.AsyncOrSyncIterable: ...
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
- ) -> modal._utils.async_utils.AsyncOrSyncIterable: ...
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
- async def aio(self, /, *input_iterators, kwargs={}) -> None: ...
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
- async def aio(self, /, timeout: typing.Optional[float] = None) -> ReturnType_INNER: ...
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
- async def aio(self, /) -> list[modal.call_graph.InputInfo]: ...
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
- async def aio(self, /, terminate_containers: bool = False): ...
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
- self, /, *function_calls: FunctionCall[modal._functions.T]
371
- ) -> typing.Sequence[modal._functions.T]: ...
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
- async def aio(self, /, *function_calls) -> typing.Sequence[modal._functions.T]: ...
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