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/app.pyi CHANGED
@@ -1,5 +1,6 @@
1
1
  import collections.abc
2
2
  import modal._functions
3
+ import modal._load_context
3
4
  import modal._partial_function
4
5
  import modal._utils.function_utils
5
6
  import modal.client
@@ -26,8 +27,14 @@ class _LocalEntrypoint:
26
27
  _info: modal._utils.function_utils.FunctionInfo
27
28
  _app: _App
28
29
 
29
- def __init__(self, info: modal._utils.function_utils.FunctionInfo, app: _App) -> None: ...
30
- def __call__(self, *args: typing.Any, **kwargs: typing.Any) -> typing.Any: ...
30
+ def __init__(self, info: modal._utils.function_utils.FunctionInfo, app: _App) -> None:
31
+ """Initialize self. See help(type(self)) for accurate signature."""
32
+ ...
33
+
34
+ def __call__(self, *args: typing.Any, **kwargs: typing.Any) -> typing.Any:
35
+ """Call self as a function."""
36
+ ...
37
+
31
38
  @property
32
39
  def info(self) -> modal._utils.function_utils.FunctionInfo: ...
33
40
  @property
@@ -68,40 +75,134 @@ class _FunctionDecoratorType:
68
75
  self, func: collections.abc.Callable[P, ReturnType]
69
76
  ) -> modal.functions.Function[P, ReturnType, ReturnType]: ...
70
77
 
78
+ class _LocalAppState:
79
+ """All state for apps that's part of the local/definition state"""
80
+
81
+ functions: dict[str, modal._functions._Function]
82
+ classes: dict[str, modal.cls._Cls]
83
+ image_default: typing.Optional[modal.image._Image]
84
+ web_endpoints: list[str]
85
+ local_entrypoints: dict[str, _LocalEntrypoint]
86
+ tags: dict[str, str]
87
+ include_source_default: bool
88
+ secrets_default: collections.abc.Sequence[modal.secret._Secret]
89
+ volumes_default: dict[typing.Union[str, pathlib.PurePosixPath], modal.volume._Volume]
90
+
91
+ def __init__(
92
+ self,
93
+ functions: dict[str, modal._functions._Function],
94
+ classes: dict[str, modal.cls._Cls],
95
+ image_default: typing.Optional[modal.image._Image],
96
+ web_endpoints: list[str],
97
+ local_entrypoints: dict[str, _LocalEntrypoint],
98
+ tags: dict[str, str],
99
+ include_source_default: bool,
100
+ secrets_default: collections.abc.Sequence[modal.secret._Secret],
101
+ volumes_default: dict[typing.Union[str, pathlib.PurePosixPath], modal.volume._Volume],
102
+ ) -> None:
103
+ """Initialize self. See help(type(self)) for accurate signature."""
104
+ ...
105
+
106
+ def __repr__(self):
107
+ """Return repr(self)."""
108
+ ...
109
+
110
+ def __eq__(self, other):
111
+ """Return self==value."""
112
+ ...
113
+
71
114
  class _App:
115
+ """A Modal App is a group of functions and classes that are deployed together.
116
+
117
+ The app serves at least three purposes:
118
+
119
+ * A unit of deployment for functions and classes.
120
+ * Syncing of identities of (primarily) functions and classes across processes
121
+ (your local Python interpreter and every Modal container active in your application).
122
+ * Manage log collection for everything that happens inside your code.
123
+
124
+ **Registering functions with an app**
125
+
126
+ The most common way to explicitly register an Object with an app is through the
127
+ `@app.function()` decorator. It both registers the annotated function itself and
128
+ other passed objects, like schedules and secrets, with the app:
129
+
130
+ ```python
131
+ import modal
132
+
133
+ app = modal.App()
134
+
135
+ @app.function(
136
+ secrets=[modal.Secret.from_name("some_secret")],
137
+ schedule=modal.Period(days=1),
138
+ )
139
+ def foo():
140
+ pass
141
+ ```
142
+
143
+ In this example, the secret and schedule are registered with the app.
144
+ """
145
+
72
146
  _all_apps: typing.ClassVar[dict[typing.Optional[str], list[_App]]]
73
147
  _container_app: typing.ClassVar[typing.Optional[_App]]
74
148
  _name: typing.Optional[str]
75
149
  _description: typing.Optional[str]
76
- _functions: dict[str, modal._functions._Function]
77
- _classes: dict[str, modal.cls._Cls]
78
- _image: typing.Optional[modal.image._Image]
79
- _secrets: collections.abc.Sequence[modal.secret._Secret]
80
- _volumes: dict[typing.Union[str, pathlib.PurePosixPath], modal.volume._Volume]
81
- _web_endpoints: list[str]
82
- _local_entrypoints: dict[str, _LocalEntrypoint]
150
+ _local_state_attr: typing.Optional[_LocalAppState]
83
151
  _app_id: typing.Optional[str]
84
152
  _running_app: typing.Optional[modal.running_app.RunningApp]
85
153
  _client: typing.Optional[modal.client._Client]
86
- _include_source_default: typing.Optional[bool]
154
+ _root_load_context: modal._load_context.LoadContext
155
+
156
+ @property
157
+ def _local_state(self) -> _LocalAppState:
158
+ """For internal use only. Do not use this property directly."""
159
+ ...
87
160
 
88
161
  def __init__(
89
162
  self,
90
163
  name: typing.Optional[str] = None,
91
164
  *,
165
+ tags: typing.Optional[dict[str, str]] = None,
92
166
  image: typing.Optional[modal.image._Image] = None,
93
167
  secrets: collections.abc.Sequence[modal.secret._Secret] = [],
94
168
  volumes: dict[typing.Union[str, pathlib.PurePosixPath], modal.volume._Volume] = {},
95
- include_source: typing.Optional[bool] = None,
96
- ) -> None: ...
169
+ include_source: bool = True,
170
+ ) -> None:
171
+ """Construct a new app, optionally with default image, mounts, secrets, or volumes.
172
+
173
+ ```python notest
174
+ image = modal.Image.debian_slim().pip_install(...)
175
+ secret = modal.Secret.from_name("my-secret")
176
+ volume = modal.Volume.from_name("my-data")
177
+ app = modal.App(image=image, secrets=[secret], volumes={"/mnt/data": volume})
178
+ ```
179
+ """
180
+ ...
181
+
97
182
  @property
98
- def name(self) -> typing.Optional[str]: ...
183
+ def name(self) -> typing.Optional[str]:
184
+ """The user-provided name of the App."""
185
+ ...
186
+
99
187
  @property
100
- def is_interactive(self) -> bool: ...
188
+ def is_interactive(self) -> bool:
189
+ """mdmd:hidden
190
+ Whether the current app for the app is running in interactive mode.
191
+
192
+ Note: this method will likely be deprecated in the future.
193
+ """
194
+ ...
195
+
101
196
  @property
102
- def app_id(self) -> typing.Optional[str]: ...
197
+ def app_id(self) -> typing.Optional[str]:
198
+ """Return the app_id of a running or stopped app."""
199
+ ...
200
+
103
201
  @property
104
- def description(self) -> typing.Optional[str]: ...
202
+ def description(self) -> typing.Optional[str]:
203
+ """The App's `name`, if available, or a fallback descriptive identifier."""
204
+ ...
205
+
105
206
  @staticmethod
106
207
  async def lookup(
107
208
  name: str,
@@ -109,13 +210,44 @@ class _App:
109
210
  client: typing.Optional[modal.client._Client] = None,
110
211
  environment_name: typing.Optional[str] = None,
111
212
  create_if_missing: bool = False,
112
- ) -> _App: ...
113
- def set_description(self, description: str): ...
213
+ ) -> _App:
214
+ """Look up an App with a given name, creating a new App if necessary.
215
+
216
+ Note that Apps created through this method will be in a deployed state,
217
+ but they will not have any associated Functions or Classes. This method
218
+ is mainly useful for creating an App to associate with a Sandbox:
219
+
220
+ ```python
221
+ app = modal.App.lookup("my-app", create_if_missing=True)
222
+ modal.Sandbox.create("echo", "hi", app=app)
223
+ ```
224
+ """
225
+ ...
226
+
227
+ def set_description(self, description: str):
228
+ """mdmd:hidden
229
+ Set the description of the App before it starts running.
230
+
231
+ Note: we don't recommend using the method and may deprecate it in the future.
232
+ """
233
+ ...
234
+
114
235
  def _validate_blueprint_value(self, key: str, value: typing.Any): ...
115
236
  @property
116
- def image(self) -> modal.image._Image: ...
237
+ def image(self) -> modal.image._Image:
238
+ """mdmd:hidden
239
+ Retrieve the Image that will be used as the default for any Functions registered to the App.
240
+
241
+ Note: This property is only relevant in the build phase and won't be populated on a deployed
242
+ App that is retrieved via `modal.App.lookup`. It is likely to be deprecated in the future.
243
+ """
244
+ ...
245
+
117
246
  @image.setter
118
- def image(self, value): ...
247
+ def image(self, value):
248
+ """mdmd:hidden"""
249
+ ...
250
+
119
251
  def _uncreate_all_objects(self): ...
120
252
  def _set_local_app(
121
253
  self, client: modal.client._Client, running_app: modal.running_app.RunningApp
@@ -127,7 +259,47 @@ class _App:
127
259
  detach: bool = False,
128
260
  interactive: bool = False,
129
261
  environment_name: typing.Optional[str] = None,
130
- ) -> typing.AsyncContextManager[_App]: ...
262
+ ) -> typing.AsyncContextManager[_App]:
263
+ """Context manager that runs an ephemeral app on Modal.
264
+
265
+ Use this as the main entry point for your Modal application. All calls
266
+ to Modal Functions should be made within the scope of this context
267
+ manager, and they will correspond to the current App.
268
+
269
+ **Example**
270
+
271
+ ```python notest
272
+ with app.run():
273
+ some_modal_function.remote()
274
+ ```
275
+
276
+ To enable output printing (i.e., to see App logs), use `modal.enable_output()`:
277
+
278
+ ```python notest
279
+ with modal.enable_output():
280
+ with app.run():
281
+ some_modal_function.remote()
282
+ ```
283
+
284
+ Note that you should not invoke this in global scope of a file where you have
285
+ Modal Functions or Classes defined, since that would run the block when the Function
286
+ or Cls is imported in your containers as well. If you want to run it as your entrypoint,
287
+ consider protecting it:
288
+
289
+ ```python
290
+ if __name__ == "__main__":
291
+ with app.run():
292
+ some_modal_function.remote()
293
+ ```
294
+
295
+ You can then run your script with:
296
+
297
+ ```shell
298
+ python app_module.py
299
+ ```
300
+ """
301
+ ...
302
+
131
303
  async def deploy(
132
304
  self,
133
305
  *,
@@ -135,30 +307,162 @@ class _App:
135
307
  environment_name: typing.Optional[str] = None,
136
308
  tag: str = "",
137
309
  client: typing.Optional[modal.client._Client] = None,
138
- ) -> typing_extensions.Self: ...
310
+ ) -> typing_extensions.Self:
311
+ """Deploy the App so that it is available persistently.
312
+
313
+ Deployed Apps will be avaible for lookup or web-based invocations until they are stopped.
314
+ Unlike with `App.run`, this method will return as soon as the deployment completes.
315
+
316
+ This method is a programmatic alternative to the `modal deploy` CLI command.
317
+
318
+ Examples:
319
+
320
+ ```python notest
321
+ app = App("my-app")
322
+ app.deploy()
323
+ ```
324
+
325
+ To enable output printing (i.e., to see build logs), use `modal.enable_output()`:
326
+
327
+ ```python notest
328
+ app = App("my-app")
329
+ with modal.enable_output():
330
+ app.deploy()
331
+ ```
332
+
333
+ Unlike with `App.run`, Function logs will not stream back to the local client after the
334
+ App is deployed.
335
+
336
+ Note that you should not invoke this method in global scope, as that would redeploy
337
+ the App every time the file is imported. If you want to write a programmatic deployment
338
+ script, protect this call so that it only runs when the file is executed directly:
339
+
340
+ ```python notest
341
+ if __name__ == "__main__":
342
+ with modal.enable_output():
343
+ app.deploy()
344
+ ```
345
+
346
+ Then you can deploy your app with:
347
+
348
+ ```shell
349
+ python app_module.py
350
+ ```
351
+ """
352
+ ...
353
+
139
354
  def _get_default_image(self): ...
140
355
  def _get_watch_mounts(self): ...
141
356
  def _add_function(self, function: modal._functions._Function, is_web_endpoint: bool): ...
142
357
  def _add_class(self, tag: str, cls: modal.cls._Cls): ...
143
358
  def _init_container(self, client: modal.client._Client, running_app: modal.running_app.RunningApp): ...
144
359
  @property
145
- def registered_functions(self) -> dict[str, modal._functions._Function]: ...
360
+ def registered_functions(self) -> dict[str, modal._functions._Function]:
361
+ """mdmd:hidden
362
+ All modal.Function objects registered on the app.
363
+
364
+ Note: this property is populated only during the build phase, and it is not
365
+ expected to work when a deplyoed App has been retrieved via `modal.App.lookup`.
366
+ This method is likely to be deprecated in the future in favor of a different
367
+ approach for retrieving the layout of a deployed App.
368
+ """
369
+ ...
370
+
146
371
  @property
147
- def registered_classes(self) -> dict[str, modal.cls._Cls]: ...
372
+ def registered_classes(self) -> dict[str, modal.cls._Cls]:
373
+ """mdmd:hidden
374
+ All modal.Cls objects registered on the app.
375
+
376
+ Note: this property is populated only during the build phase, and it is not
377
+ expected to work when a deplyoed App has been retrieved via `modal.App.lookup`.
378
+ This method is likely to be deprecated in the future in favor of a different
379
+ approach for retrieving the layout of a deployed App.
380
+ """
381
+ ...
382
+
148
383
  @property
149
- def registered_entrypoints(self) -> dict[str, _LocalEntrypoint]: ...
384
+ def registered_entrypoints(self) -> dict[str, _LocalEntrypoint]:
385
+ """mdmd:hidden
386
+ All local CLI entrypoints registered on the app.
387
+
388
+ Note: this property is populated only during the build phase, and it is not
389
+ expected to work when a deplyoed App has been retrieved via `modal.App.lookup`.
390
+ This method is likely to be deprecated in the future.
391
+ """
392
+ ...
393
+
150
394
  @property
151
- def registered_web_endpoints(self) -> list[str]: ...
395
+ def registered_web_endpoints(self) -> list[str]:
396
+ """mdmd:hidden
397
+ Names of web endpoint (ie. webhook) functions registered on the app.
398
+
399
+ Note: this property is populated only during the build phase, and it is not
400
+ expected to work when a deplyoed App has been retrieved via `modal.App.lookup`.
401
+ This method is likely to be deprecated in the future in favor of a different
402
+ approach for retrieving the layout of a deployed App.
403
+ """
404
+ ...
405
+
152
406
  def local_entrypoint(
153
407
  self, _warn_parentheses_missing: typing.Any = None, *, name: typing.Optional[str] = None
154
- ) -> collections.abc.Callable[[collections.abc.Callable[..., typing.Any]], _LocalEntrypoint]: ...
408
+ ) -> collections.abc.Callable[[collections.abc.Callable[..., typing.Any]], _LocalEntrypoint]:
409
+ """Decorate a function to be used as a CLI entrypoint for a Modal App.
410
+
411
+ These functions can be used to define code that runs locally to set up the app,
412
+ and act as an entrypoint to start Modal functions from. Note that regular
413
+ Modal functions can also be used as CLI entrypoints, but unlike `local_entrypoint`,
414
+ those functions are executed remotely directly.
415
+
416
+ **Example**
417
+
418
+ ```python
419
+ @app.local_entrypoint()
420
+ def main():
421
+ some_modal_function.remote()
422
+ ```
423
+
424
+ You can call the function using `modal run` directly from the CLI:
425
+
426
+ ```shell
427
+ modal run app_module.py
428
+ ```
429
+
430
+ Note that an explicit [`app.run()`](https://modal.com/docs/reference/modal.App#run) is not needed, as an
431
+ [app](https://modal.com/docs/guide/apps) is automatically created for you.
432
+
433
+ **Multiple Entrypoints**
434
+
435
+ If you have multiple `local_entrypoint` functions, you can qualify the name of your app and function:
436
+
437
+ ```shell
438
+ modal run app_module.py::app.some_other_function
439
+ ```
440
+
441
+ **Parsing Arguments**
442
+
443
+ If your entrypoint function take arguments with primitive types, `modal run` automatically parses them as
444
+ CLI options.
445
+ For example, the following function can be called with `modal run app_module.py --foo 1 --bar "hello"`:
446
+
447
+ ```python
448
+ @app.local_entrypoint()
449
+ def main(foo: int, bar: str):
450
+ some_modal_function.call(foo, bar)
451
+ ```
452
+
453
+ Currently, `str`, `int`, `float`, `bool`, and `datetime.datetime` are supported.
454
+ Use `modal run app_module.py --help` for more information on usage.
455
+ """
456
+ ...
457
+
155
458
  def function(
156
459
  self,
157
- _warn_parentheses_missing: typing.Any = None,
460
+ _warn_parentheses_missing=None,
158
461
  *,
159
462
  image: typing.Optional[modal.image._Image] = None,
160
463
  schedule: typing.Optional[modal.schedule.Schedule] = None,
161
- secrets: collections.abc.Sequence[modal.secret._Secret] = (),
464
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
465
+ secrets: typing.Optional[collections.abc.Collection[modal.secret._Secret]] = None,
162
466
  gpu: typing.Union[None, str, modal.gpu._GPUConfig, list[typing.Union[None, str, modal.gpu._GPUConfig]]] = None,
163
467
  serialized: bool = False,
164
468
  network_file_systems: dict[
@@ -177,7 +481,8 @@ class _App:
177
481
  scaledown_window: typing.Optional[int] = None,
178
482
  proxy: typing.Optional[modal.proxy._Proxy] = None,
179
483
  retries: typing.Union[int, modal.retries.Retries, None] = None,
180
- timeout: typing.Optional[int] = None,
484
+ timeout: int = 300,
485
+ startup_timeout: typing.Optional[int] = None,
181
486
  name: typing.Optional[str] = None,
182
487
  is_generator: typing.Optional[bool] = None,
183
488
  cloud: typing.Optional[str] = None,
@@ -192,24 +497,27 @@ class _App:
192
497
  _experimental_scheduler_placement: typing.Optional[modal.scheduler_placement.SchedulerPlacement] = None,
193
498
  _experimental_proxy_ip: typing.Optional[str] = None,
194
499
  _experimental_custom_scaling_factor: typing.Optional[float] = None,
195
- _experimental_enable_gpu_snapshot: bool = False,
500
+ _experimental_restrict_output: bool = False,
196
501
  keep_warm: typing.Optional[int] = None,
197
502
  concurrency_limit: typing.Optional[int] = None,
198
503
  container_idle_timeout: typing.Optional[int] = None,
199
504
  allow_concurrent_inputs: typing.Optional[int] = None,
200
505
  _experimental_buffer_containers: typing.Optional[int] = None,
201
- allow_cross_region_volumes: typing.Optional[bool] = None,
202
- ) -> _FunctionDecoratorType: ...
506
+ ) -> _FunctionDecoratorType:
507
+ """Decorator to register a new Modal Function with this App."""
508
+ ...
509
+
203
510
  @typing_extensions.dataclass_transform(
204
511
  field_specifiers=(modal.cls.parameter,),
205
512
  kw_only_default=True,
206
513
  )
207
514
  def cls(
208
515
  self,
209
- _warn_parentheses_missing: typing.Optional[bool] = None,
516
+ _warn_parentheses_missing=None,
210
517
  *,
211
518
  image: typing.Optional[modal.image._Image] = None,
212
- secrets: collections.abc.Sequence[modal.secret._Secret] = (),
519
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
520
+ secrets: typing.Optional[collections.abc.Collection[modal.secret._Secret]] = None,
213
521
  gpu: typing.Union[None, str, modal.gpu._GPUConfig, list[typing.Union[None, str, modal.gpu._GPUConfig]]] = None,
214
522
  serialized: bool = False,
215
523
  network_file_systems: dict[
@@ -228,71 +536,190 @@ class _App:
228
536
  scaledown_window: typing.Optional[int] = None,
229
537
  proxy: typing.Optional[modal.proxy._Proxy] = None,
230
538
  retries: typing.Union[int, modal.retries.Retries, None] = None,
231
- timeout: typing.Optional[int] = None,
539
+ timeout: int = 300,
540
+ startup_timeout: typing.Optional[int] = None,
232
541
  cloud: typing.Optional[str] = None,
233
542
  region: typing.Union[str, collections.abc.Sequence[str], None] = None,
234
543
  enable_memory_snapshot: bool = False,
235
544
  block_network: bool = False,
236
545
  restrict_modal_access: bool = False,
237
546
  max_inputs: typing.Optional[int] = None,
547
+ i6pn: typing.Optional[bool] = None,
238
548
  include_source: typing.Optional[bool] = None,
239
549
  experimental_options: typing.Optional[dict[str, typing.Any]] = None,
240
550
  _experimental_scheduler_placement: typing.Optional[modal.scheduler_placement.SchedulerPlacement] = None,
241
551
  _experimental_proxy_ip: typing.Optional[str] = None,
242
552
  _experimental_custom_scaling_factor: typing.Optional[float] = None,
243
- _experimental_enable_gpu_snapshot: bool = False,
553
+ _experimental_restrict_output: bool = False,
244
554
  keep_warm: typing.Optional[int] = None,
245
555
  concurrency_limit: typing.Optional[int] = None,
246
556
  container_idle_timeout: typing.Optional[int] = None,
247
557
  allow_concurrent_inputs: typing.Optional[int] = None,
248
558
  _experimental_buffer_containers: typing.Optional[int] = None,
249
- allow_cross_region_volumes: typing.Optional[bool] = None,
250
- ) -> collections.abc.Callable[[typing.Union[CLS_T, modal._partial_function._PartialFunction]], CLS_T]: ...
251
- def include(self, /, other_app: _App) -> typing_extensions.Self: ...
252
- def _logs(
253
- self, client: typing.Optional[modal.client._Client] = None
254
- ) -> collections.abc.AsyncGenerator[str, None]: ...
559
+ ) -> collections.abc.Callable[[typing.Union[CLS_T, modal._partial_function._PartialFunction]], CLS_T]:
560
+ """Decorator to register a new Modal [Cls](https://modal.com/docs/reference/modal.Cls) with this App."""
561
+ ...
562
+
563
+ def include(self, /, other_app: _App, inherit_tags: bool = True) -> typing_extensions.Self:
564
+ """Include another App's objects in this one.
565
+
566
+ Useful for splitting up Modal Apps across different self-contained files.
567
+
568
+ ```python
569
+ app_a = modal.App("a")
570
+ @app.function()
571
+ def foo():
572
+ ...
573
+
574
+ app_b = modal.App("b")
575
+ @app.function()
576
+ def bar():
577
+ ...
578
+
579
+ app_a.include(app_b)
580
+
581
+ @app_a.local_entrypoint()
582
+ def main():
583
+ # use function declared on the included app
584
+ bar.remote()
585
+ ```
586
+
587
+ When `inherit_tags=True` any tags set on the other App will be inherited by this App
588
+ (with this App's tags taking precedence in the case of conflicts).
589
+ """
590
+ ...
591
+
592
+ async def set_tags(
593
+ self, tags: collections.abc.Mapping[str, str], *, client: typing.Optional[modal.client._Client] = None
594
+ ) -> None:
595
+ """Attach key-value metadata to the App.
596
+
597
+ Tag metadata can be used to add organization-specific context to the App and can be
598
+ included in billing reports and other informational APIs. Tags can also be set in
599
+ the App constructor.
600
+
601
+ Any tags set on the App before calling this method will be removed if they are not
602
+ included in the argument (i.e., this method does not have `.update()` semantics).
603
+ """
604
+ ...
605
+
606
+ async def get_tags(self, *, client: typing.Optional[modal.client._Client] = None) -> dict[str, str]:
607
+ """Get the tags that are currently attached to the App."""
608
+ ...
609
+
610
+ def _logs(self, client: typing.Optional[modal.client._Client] = None) -> collections.abc.AsyncGenerator[str, None]:
611
+ """Stream logs from the app.
612
+
613
+ This method is considered private and its interface may change - use at your own risk!
614
+ """
615
+ ...
616
+
255
617
  @classmethod
256
- def _get_container_app(cls) -> typing.Optional[_App]: ...
618
+ def _get_container_app(cls) -> typing.Optional[_App]:
619
+ """Returns the `App` running inside a container.
620
+
621
+ This will return `None` outside of a Modal container.
622
+ """
623
+ ...
624
+
257
625
  @classmethod
258
- def _reset_container_app(cls): ...
626
+ def _reset_container_app(cls):
627
+ """Only used for tests."""
628
+ ...
259
629
 
260
630
  SUPERSELF = typing.TypeVar("SUPERSELF", covariant=True)
261
631
 
262
632
  class App:
633
+ """A Modal App is a group of functions and classes that are deployed together.
634
+
635
+ The app serves at least three purposes:
636
+
637
+ * A unit of deployment for functions and classes.
638
+ * Syncing of identities of (primarily) functions and classes across processes
639
+ (your local Python interpreter and every Modal container active in your application).
640
+ * Manage log collection for everything that happens inside your code.
641
+
642
+ **Registering functions with an app**
643
+
644
+ The most common way to explicitly register an Object with an app is through the
645
+ `@app.function()` decorator. It both registers the annotated function itself and
646
+ other passed objects, like schedules and secrets, with the app:
647
+
648
+ ```python
649
+ import modal
650
+
651
+ app = modal.App()
652
+
653
+ @app.function(
654
+ secrets=[modal.Secret.from_name("some_secret")],
655
+ schedule=modal.Period(days=1),
656
+ )
657
+ def foo():
658
+ pass
659
+ ```
660
+
661
+ In this example, the secret and schedule are registered with the app.
662
+ """
663
+
263
664
  _all_apps: typing.ClassVar[dict[typing.Optional[str], list[App]]]
264
665
  _container_app: typing.ClassVar[typing.Optional[App]]
265
666
  _name: typing.Optional[str]
266
667
  _description: typing.Optional[str]
267
- _functions: dict[str, modal.functions.Function]
268
- _classes: dict[str, modal.cls.Cls]
269
- _image: typing.Optional[modal.image.Image]
270
- _secrets: collections.abc.Sequence[modal.secret.Secret]
271
- _volumes: dict[typing.Union[str, pathlib.PurePosixPath], modal.volume.Volume]
272
- _web_endpoints: list[str]
273
- _local_entrypoints: dict[str, LocalEntrypoint]
668
+ _local_state_attr: typing.Optional[_LocalAppState]
274
669
  _app_id: typing.Optional[str]
275
670
  _running_app: typing.Optional[modal.running_app.RunningApp]
276
671
  _client: typing.Optional[modal.client.Client]
277
- _include_source_default: typing.Optional[bool]
672
+ _root_load_context: modal._load_context.LoadContext
278
673
 
279
674
  def __init__(
280
675
  self,
281
676
  name: typing.Optional[str] = None,
282
677
  *,
678
+ tags: typing.Optional[dict[str, str]] = None,
283
679
  image: typing.Optional[modal.image.Image] = None,
284
680
  secrets: collections.abc.Sequence[modal.secret.Secret] = [],
285
681
  volumes: dict[typing.Union[str, pathlib.PurePosixPath], modal.volume.Volume] = {},
286
- include_source: typing.Optional[bool] = None,
287
- ) -> None: ...
682
+ include_source: bool = True,
683
+ ) -> None:
684
+ """Construct a new app, optionally with default image, mounts, secrets, or volumes.
685
+
686
+ ```python notest
687
+ image = modal.Image.debian_slim().pip_install(...)
688
+ secret = modal.Secret.from_name("my-secret")
689
+ volume = modal.Volume.from_name("my-data")
690
+ app = modal.App(image=image, secrets=[secret], volumes={"/mnt/data": volume})
691
+ ```
692
+ """
693
+ ...
694
+
288
695
  @property
289
- def name(self) -> typing.Optional[str]: ...
696
+ def _local_state(self) -> _LocalAppState:
697
+ """For internal use only. Do not use this property directly."""
698
+ ...
699
+
290
700
  @property
291
- def is_interactive(self) -> bool: ...
701
+ def name(self) -> typing.Optional[str]:
702
+ """The user-provided name of the App."""
703
+ ...
704
+
705
+ @property
706
+ def is_interactive(self) -> bool:
707
+ """mdmd:hidden
708
+ Whether the current app for the app is running in interactive mode.
709
+
710
+ Note: this method will likely be deprecated in the future.
711
+ """
712
+ ...
713
+
292
714
  @property
293
- def app_id(self) -> typing.Optional[str]: ...
715
+ def app_id(self) -> typing.Optional[str]:
716
+ """Return the app_id of a running or stopped app."""
717
+ ...
718
+
294
719
  @property
295
- def description(self) -> typing.Optional[str]: ...
720
+ def description(self) -> typing.Optional[str]:
721
+ """The App's `name`, if available, or a fallback descriptive identifier."""
722
+ ...
296
723
 
297
724
  class __lookup_spec(typing_extensions.Protocol):
298
725
  def __call__(
@@ -303,7 +730,20 @@ class App:
303
730
  client: typing.Optional[modal.client.Client] = None,
304
731
  environment_name: typing.Optional[str] = None,
305
732
  create_if_missing: bool = False,
306
- ) -> App: ...
733
+ ) -> App:
734
+ """Look up an App with a given name, creating a new App if necessary.
735
+
736
+ Note that Apps created through this method will be in a deployed state,
737
+ but they will not have any associated Functions or Classes. This method
738
+ is mainly useful for creating an App to associate with a Sandbox:
739
+
740
+ ```python
741
+ app = modal.App.lookup("my-app", create_if_missing=True)
742
+ modal.Sandbox.create("echo", "hi", app=app)
743
+ ```
744
+ """
745
+ ...
746
+
307
747
  async def aio(
308
748
  self,
309
749
  /,
@@ -312,16 +752,46 @@ class App:
312
752
  client: typing.Optional[modal.client.Client] = None,
313
753
  environment_name: typing.Optional[str] = None,
314
754
  create_if_missing: bool = False,
315
- ) -> App: ...
755
+ ) -> App:
756
+ """Look up an App with a given name, creating a new App if necessary.
757
+
758
+ Note that Apps created through this method will be in a deployed state,
759
+ but they will not have any associated Functions or Classes. This method
760
+ is mainly useful for creating an App to associate with a Sandbox:
761
+
762
+ ```python
763
+ app = modal.App.lookup("my-app", create_if_missing=True)
764
+ modal.Sandbox.create("echo", "hi", app=app)
765
+ ```
766
+ """
767
+ ...
316
768
 
317
769
  lookup: __lookup_spec
318
770
 
319
- def set_description(self, description: str): ...
771
+ def set_description(self, description: str):
772
+ """mdmd:hidden
773
+ Set the description of the App before it starts running.
774
+
775
+ Note: we don't recommend using the method and may deprecate it in the future.
776
+ """
777
+ ...
778
+
320
779
  def _validate_blueprint_value(self, key: str, value: typing.Any): ...
321
780
  @property
322
- def image(self) -> modal.image.Image: ...
781
+ def image(self) -> modal.image.Image:
782
+ """mdmd:hidden
783
+ Retrieve the Image that will be used as the default for any Functions registered to the App.
784
+
785
+ Note: This property is only relevant in the build phase and won't be populated on a deployed
786
+ App that is retrieved via `modal.App.lookup`. It is likely to be deprecated in the future.
787
+ """
788
+ ...
789
+
323
790
  @image.setter
324
- def image(self, value): ...
791
+ def image(self, value):
792
+ """mdmd:hidden"""
793
+ ...
794
+
325
795
  def _uncreate_all_objects(self): ...
326
796
 
327
797
  class ___set_local_app_spec(typing_extensions.Protocol[SUPERSELF]):
@@ -343,7 +813,47 @@ class App:
343
813
  detach: bool = False,
344
814
  interactive: bool = False,
345
815
  environment_name: typing.Optional[str] = None,
346
- ) -> synchronicity.combined_types.AsyncAndBlockingContextManager[App]: ...
816
+ ) -> synchronicity.combined_types.AsyncAndBlockingContextManager[App]:
817
+ """Context manager that runs an ephemeral app on Modal.
818
+
819
+ Use this as the main entry point for your Modal application. All calls
820
+ to Modal Functions should be made within the scope of this context
821
+ manager, and they will correspond to the current App.
822
+
823
+ **Example**
824
+
825
+ ```python notest
826
+ with app.run():
827
+ some_modal_function.remote()
828
+ ```
829
+
830
+ To enable output printing (i.e., to see App logs), use `modal.enable_output()`:
831
+
832
+ ```python notest
833
+ with modal.enable_output():
834
+ with app.run():
835
+ some_modal_function.remote()
836
+ ```
837
+
838
+ Note that you should not invoke this in global scope of a file where you have
839
+ Modal Functions or Classes defined, since that would run the block when the Function
840
+ or Cls is imported in your containers as well. If you want to run it as your entrypoint,
841
+ consider protecting it:
842
+
843
+ ```python
844
+ if __name__ == "__main__":
845
+ with app.run():
846
+ some_modal_function.remote()
847
+ ```
848
+
849
+ You can then run your script with:
850
+
851
+ ```shell
852
+ python app_module.py
853
+ ```
854
+ """
855
+ ...
856
+
347
857
  def aio(
348
858
  self,
349
859
  /,
@@ -352,7 +862,46 @@ class App:
352
862
  detach: bool = False,
353
863
  interactive: bool = False,
354
864
  environment_name: typing.Optional[str] = None,
355
- ) -> typing.AsyncContextManager[App]: ...
865
+ ) -> typing.AsyncContextManager[App]:
866
+ """Context manager that runs an ephemeral app on Modal.
867
+
868
+ Use this as the main entry point for your Modal application. All calls
869
+ to Modal Functions should be made within the scope of this context
870
+ manager, and they will correspond to the current App.
871
+
872
+ **Example**
873
+
874
+ ```python notest
875
+ with app.run():
876
+ some_modal_function.remote()
877
+ ```
878
+
879
+ To enable output printing (i.e., to see App logs), use `modal.enable_output()`:
880
+
881
+ ```python notest
882
+ with modal.enable_output():
883
+ with app.run():
884
+ some_modal_function.remote()
885
+ ```
886
+
887
+ Note that you should not invoke this in global scope of a file where you have
888
+ Modal Functions or Classes defined, since that would run the block when the Function
889
+ or Cls is imported in your containers as well. If you want to run it as your entrypoint,
890
+ consider protecting it:
891
+
892
+ ```python
893
+ if __name__ == "__main__":
894
+ with app.run():
895
+ some_modal_function.remote()
896
+ ```
897
+
898
+ You can then run your script with:
899
+
900
+ ```shell
901
+ python app_module.py
902
+ ```
903
+ """
904
+ ...
356
905
 
357
906
  run: __run_spec[typing_extensions.Self]
358
907
 
@@ -365,7 +914,50 @@ class App:
365
914
  environment_name: typing.Optional[str] = None,
366
915
  tag: str = "",
367
916
  client: typing.Optional[modal.client.Client] = None,
368
- ) -> SUPERSELF: ...
917
+ ) -> SUPERSELF:
918
+ """Deploy the App so that it is available persistently.
919
+
920
+ Deployed Apps will be avaible for lookup or web-based invocations until they are stopped.
921
+ Unlike with `App.run`, this method will return as soon as the deployment completes.
922
+
923
+ This method is a programmatic alternative to the `modal deploy` CLI command.
924
+
925
+ Examples:
926
+
927
+ ```python notest
928
+ app = App("my-app")
929
+ app.deploy()
930
+ ```
931
+
932
+ To enable output printing (i.e., to see build logs), use `modal.enable_output()`:
933
+
934
+ ```python notest
935
+ app = App("my-app")
936
+ with modal.enable_output():
937
+ app.deploy()
938
+ ```
939
+
940
+ Unlike with `App.run`, Function logs will not stream back to the local client after the
941
+ App is deployed.
942
+
943
+ Note that you should not invoke this method in global scope, as that would redeploy
944
+ the App every time the file is imported. If you want to write a programmatic deployment
945
+ script, protect this call so that it only runs when the file is executed directly:
946
+
947
+ ```python notest
948
+ if __name__ == "__main__":
949
+ with modal.enable_output():
950
+ app.deploy()
951
+ ```
952
+
953
+ Then you can deploy your app with:
954
+
955
+ ```shell
956
+ python app_module.py
957
+ ```
958
+ """
959
+ ...
960
+
369
961
  async def aio(
370
962
  self,
371
963
  /,
@@ -374,7 +966,49 @@ class App:
374
966
  environment_name: typing.Optional[str] = None,
375
967
  tag: str = "",
376
968
  client: typing.Optional[modal.client.Client] = None,
377
- ) -> SUPERSELF: ...
969
+ ) -> SUPERSELF:
970
+ """Deploy the App so that it is available persistently.
971
+
972
+ Deployed Apps will be avaible for lookup or web-based invocations until they are stopped.
973
+ Unlike with `App.run`, this method will return as soon as the deployment completes.
974
+
975
+ This method is a programmatic alternative to the `modal deploy` CLI command.
976
+
977
+ Examples:
978
+
979
+ ```python notest
980
+ app = App("my-app")
981
+ app.deploy()
982
+ ```
983
+
984
+ To enable output printing (i.e., to see build logs), use `modal.enable_output()`:
985
+
986
+ ```python notest
987
+ app = App("my-app")
988
+ with modal.enable_output():
989
+ app.deploy()
990
+ ```
991
+
992
+ Unlike with `App.run`, Function logs will not stream back to the local client after the
993
+ App is deployed.
994
+
995
+ Note that you should not invoke this method in global scope, as that would redeploy
996
+ the App every time the file is imported. If you want to write a programmatic deployment
997
+ script, protect this call so that it only runs when the file is executed directly:
998
+
999
+ ```python notest
1000
+ if __name__ == "__main__":
1001
+ with modal.enable_output():
1002
+ app.deploy()
1003
+ ```
1004
+
1005
+ Then you can deploy your app with:
1006
+
1007
+ ```shell
1008
+ python app_module.py
1009
+ ```
1010
+ """
1011
+ ...
378
1012
 
379
1013
  deploy: __deploy_spec[typing_extensions.Self]
380
1014
 
@@ -384,23 +1018,112 @@ class App:
384
1018
  def _add_class(self, tag: str, cls: modal.cls.Cls): ...
385
1019
  def _init_container(self, client: modal.client.Client, running_app: modal.running_app.RunningApp): ...
386
1020
  @property
387
- def registered_functions(self) -> dict[str, modal.functions.Function]: ...
1021
+ def registered_functions(self) -> dict[str, modal.functions.Function]:
1022
+ """mdmd:hidden
1023
+ All modal.Function objects registered on the app.
1024
+
1025
+ Note: this property is populated only during the build phase, and it is not
1026
+ expected to work when a deplyoed App has been retrieved via `modal.App.lookup`.
1027
+ This method is likely to be deprecated in the future in favor of a different
1028
+ approach for retrieving the layout of a deployed App.
1029
+ """
1030
+ ...
1031
+
388
1032
  @property
389
- def registered_classes(self) -> dict[str, modal.cls.Cls]: ...
1033
+ def registered_classes(self) -> dict[str, modal.cls.Cls]:
1034
+ """mdmd:hidden
1035
+ All modal.Cls objects registered on the app.
1036
+
1037
+ Note: this property is populated only during the build phase, and it is not
1038
+ expected to work when a deplyoed App has been retrieved via `modal.App.lookup`.
1039
+ This method is likely to be deprecated in the future in favor of a different
1040
+ approach for retrieving the layout of a deployed App.
1041
+ """
1042
+ ...
1043
+
390
1044
  @property
391
- def registered_entrypoints(self) -> dict[str, LocalEntrypoint]: ...
1045
+ def registered_entrypoints(self) -> dict[str, LocalEntrypoint]:
1046
+ """mdmd:hidden
1047
+ All local CLI entrypoints registered on the app.
1048
+
1049
+ Note: this property is populated only during the build phase, and it is not
1050
+ expected to work when a deplyoed App has been retrieved via `modal.App.lookup`.
1051
+ This method is likely to be deprecated in the future.
1052
+ """
1053
+ ...
1054
+
392
1055
  @property
393
- def registered_web_endpoints(self) -> list[str]: ...
1056
+ def registered_web_endpoints(self) -> list[str]:
1057
+ """mdmd:hidden
1058
+ Names of web endpoint (ie. webhook) functions registered on the app.
1059
+
1060
+ Note: this property is populated only during the build phase, and it is not
1061
+ expected to work when a deplyoed App has been retrieved via `modal.App.lookup`.
1062
+ This method is likely to be deprecated in the future in favor of a different
1063
+ approach for retrieving the layout of a deployed App.
1064
+ """
1065
+ ...
1066
+
394
1067
  def local_entrypoint(
395
1068
  self, _warn_parentheses_missing: typing.Any = None, *, name: typing.Optional[str] = None
396
- ) -> collections.abc.Callable[[collections.abc.Callable[..., typing.Any]], LocalEntrypoint]: ...
1069
+ ) -> collections.abc.Callable[[collections.abc.Callable[..., typing.Any]], LocalEntrypoint]:
1070
+ """Decorate a function to be used as a CLI entrypoint for a Modal App.
1071
+
1072
+ These functions can be used to define code that runs locally to set up the app,
1073
+ and act as an entrypoint to start Modal functions from. Note that regular
1074
+ Modal functions can also be used as CLI entrypoints, but unlike `local_entrypoint`,
1075
+ those functions are executed remotely directly.
1076
+
1077
+ **Example**
1078
+
1079
+ ```python
1080
+ @app.local_entrypoint()
1081
+ def main():
1082
+ some_modal_function.remote()
1083
+ ```
1084
+
1085
+ You can call the function using `modal run` directly from the CLI:
1086
+
1087
+ ```shell
1088
+ modal run app_module.py
1089
+ ```
1090
+
1091
+ Note that an explicit [`app.run()`](https://modal.com/docs/reference/modal.App#run) is not needed, as an
1092
+ [app](https://modal.com/docs/guide/apps) is automatically created for you.
1093
+
1094
+ **Multiple Entrypoints**
1095
+
1096
+ If you have multiple `local_entrypoint` functions, you can qualify the name of your app and function:
1097
+
1098
+ ```shell
1099
+ modal run app_module.py::app.some_other_function
1100
+ ```
1101
+
1102
+ **Parsing Arguments**
1103
+
1104
+ If your entrypoint function take arguments with primitive types, `modal run` automatically parses them as
1105
+ CLI options.
1106
+ For example, the following function can be called with `modal run app_module.py --foo 1 --bar "hello"`:
1107
+
1108
+ ```python
1109
+ @app.local_entrypoint()
1110
+ def main(foo: int, bar: str):
1111
+ some_modal_function.call(foo, bar)
1112
+ ```
1113
+
1114
+ Currently, `str`, `int`, `float`, `bool`, and `datetime.datetime` are supported.
1115
+ Use `modal run app_module.py --help` for more information on usage.
1116
+ """
1117
+ ...
1118
+
397
1119
  def function(
398
1120
  self,
399
- _warn_parentheses_missing: typing.Any = None,
1121
+ _warn_parentheses_missing=None,
400
1122
  *,
401
1123
  image: typing.Optional[modal.image.Image] = None,
402
1124
  schedule: typing.Optional[modal.schedule.Schedule] = None,
403
- secrets: collections.abc.Sequence[modal.secret.Secret] = (),
1125
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
1126
+ secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
404
1127
  gpu: typing.Union[None, str, modal.gpu._GPUConfig, list[typing.Union[None, str, modal.gpu._GPUConfig]]] = None,
405
1128
  serialized: bool = False,
406
1129
  network_file_systems: dict[
@@ -419,7 +1142,8 @@ class App:
419
1142
  scaledown_window: typing.Optional[int] = None,
420
1143
  proxy: typing.Optional[modal.proxy.Proxy] = None,
421
1144
  retries: typing.Union[int, modal.retries.Retries, None] = None,
422
- timeout: typing.Optional[int] = None,
1145
+ timeout: int = 300,
1146
+ startup_timeout: typing.Optional[int] = None,
423
1147
  name: typing.Optional[str] = None,
424
1148
  is_generator: typing.Optional[bool] = None,
425
1149
  cloud: typing.Optional[str] = None,
@@ -434,24 +1158,27 @@ class App:
434
1158
  _experimental_scheduler_placement: typing.Optional[modal.scheduler_placement.SchedulerPlacement] = None,
435
1159
  _experimental_proxy_ip: typing.Optional[str] = None,
436
1160
  _experimental_custom_scaling_factor: typing.Optional[float] = None,
437
- _experimental_enable_gpu_snapshot: bool = False,
1161
+ _experimental_restrict_output: bool = False,
438
1162
  keep_warm: typing.Optional[int] = None,
439
1163
  concurrency_limit: typing.Optional[int] = None,
440
1164
  container_idle_timeout: typing.Optional[int] = None,
441
1165
  allow_concurrent_inputs: typing.Optional[int] = None,
442
1166
  _experimental_buffer_containers: typing.Optional[int] = None,
443
- allow_cross_region_volumes: typing.Optional[bool] = None,
444
- ) -> _FunctionDecoratorType: ...
1167
+ ) -> _FunctionDecoratorType:
1168
+ """Decorator to register a new Modal Function with this App."""
1169
+ ...
1170
+
445
1171
  @typing_extensions.dataclass_transform(
446
1172
  field_specifiers=(modal.cls.parameter,),
447
1173
  kw_only_default=True,
448
1174
  )
449
1175
  def cls(
450
1176
  self,
451
- _warn_parentheses_missing: typing.Optional[bool] = None,
1177
+ _warn_parentheses_missing=None,
452
1178
  *,
453
1179
  image: typing.Optional[modal.image.Image] = None,
454
- secrets: collections.abc.Sequence[modal.secret.Secret] = (),
1180
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
1181
+ secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
455
1182
  gpu: typing.Union[None, str, modal.gpu._GPUConfig, list[typing.Union[None, str, modal.gpu._GPUConfig]]] = None,
456
1183
  serialized: bool = False,
457
1184
  network_file_systems: dict[
@@ -470,41 +1197,131 @@ class App:
470
1197
  scaledown_window: typing.Optional[int] = None,
471
1198
  proxy: typing.Optional[modal.proxy.Proxy] = None,
472
1199
  retries: typing.Union[int, modal.retries.Retries, None] = None,
473
- timeout: typing.Optional[int] = None,
1200
+ timeout: int = 300,
1201
+ startup_timeout: typing.Optional[int] = None,
474
1202
  cloud: typing.Optional[str] = None,
475
1203
  region: typing.Union[str, collections.abc.Sequence[str], None] = None,
476
1204
  enable_memory_snapshot: bool = False,
477
1205
  block_network: bool = False,
478
1206
  restrict_modal_access: bool = False,
479
1207
  max_inputs: typing.Optional[int] = None,
1208
+ i6pn: typing.Optional[bool] = None,
480
1209
  include_source: typing.Optional[bool] = None,
481
1210
  experimental_options: typing.Optional[dict[str, typing.Any]] = None,
482
1211
  _experimental_scheduler_placement: typing.Optional[modal.scheduler_placement.SchedulerPlacement] = None,
483
1212
  _experimental_proxy_ip: typing.Optional[str] = None,
484
1213
  _experimental_custom_scaling_factor: typing.Optional[float] = None,
485
- _experimental_enable_gpu_snapshot: bool = False,
1214
+ _experimental_restrict_output: bool = False,
486
1215
  keep_warm: typing.Optional[int] = None,
487
1216
  concurrency_limit: typing.Optional[int] = None,
488
1217
  container_idle_timeout: typing.Optional[int] = None,
489
1218
  allow_concurrent_inputs: typing.Optional[int] = None,
490
1219
  _experimental_buffer_containers: typing.Optional[int] = None,
491
- allow_cross_region_volumes: typing.Optional[bool] = None,
492
- ) -> collections.abc.Callable[[typing.Union[CLS_T, modal.partial_function.PartialFunction]], CLS_T]: ...
493
- def include(self, /, other_app: App) -> typing_extensions.Self: ...
1220
+ ) -> collections.abc.Callable[[typing.Union[CLS_T, modal.partial_function.PartialFunction]], CLS_T]:
1221
+ """Decorator to register a new Modal [Cls](https://modal.com/docs/reference/modal.Cls) with this App."""
1222
+ ...
494
1223
 
495
- class ___logs_spec(typing_extensions.Protocol[SUPERSELF]):
1224
+ def include(self, /, other_app: App, inherit_tags: bool = True) -> typing_extensions.Self:
1225
+ """Include another App's objects in this one.
1226
+
1227
+ Useful for splitting up Modal Apps across different self-contained files.
1228
+
1229
+ ```python
1230
+ app_a = modal.App("a")
1231
+ @app.function()
1232
+ def foo():
1233
+ ...
1234
+
1235
+ app_b = modal.App("b")
1236
+ @app.function()
1237
+ def bar():
1238
+ ...
1239
+
1240
+ app_a.include(app_b)
1241
+
1242
+ @app_a.local_entrypoint()
1243
+ def main():
1244
+ # use function declared on the included app
1245
+ bar.remote()
1246
+ ```
1247
+
1248
+ When `inherit_tags=True` any tags set on the other App will be inherited by this App
1249
+ (with this App's tags taking precedence in the case of conflicts).
1250
+ """
1251
+ ...
1252
+
1253
+ class __set_tags_spec(typing_extensions.Protocol[SUPERSELF]):
496
1254
  def __call__(
497
- self, /, client: typing.Optional[modal.client.Client] = None
498
- ) -> typing.Generator[str, None, None]: ...
1255
+ self, /, tags: collections.abc.Mapping[str, str], *, client: typing.Optional[modal.client.Client] = None
1256
+ ) -> None:
1257
+ """Attach key-value metadata to the App.
1258
+
1259
+ Tag metadata can be used to add organization-specific context to the App and can be
1260
+ included in billing reports and other informational APIs. Tags can also be set in
1261
+ the App constructor.
1262
+
1263
+ Any tags set on the App before calling this method will be removed if they are not
1264
+ included in the argument (i.e., this method does not have `.update()` semantics).
1265
+ """
1266
+ ...
1267
+
1268
+ async def aio(
1269
+ self, /, tags: collections.abc.Mapping[str, str], *, client: typing.Optional[modal.client.Client] = None
1270
+ ) -> None:
1271
+ """Attach key-value metadata to the App.
1272
+
1273
+ Tag metadata can be used to add organization-specific context to the App and can be
1274
+ included in billing reports and other informational APIs. Tags can also be set in
1275
+ the App constructor.
1276
+
1277
+ Any tags set on the App before calling this method will be removed if they are not
1278
+ included in the argument (i.e., this method does not have `.update()` semantics).
1279
+ """
1280
+ ...
1281
+
1282
+ set_tags: __set_tags_spec[typing_extensions.Self]
1283
+
1284
+ class __get_tags_spec(typing_extensions.Protocol[SUPERSELF]):
1285
+ def __call__(self, /, *, client: typing.Optional[modal.client.Client] = None) -> dict[str, str]:
1286
+ """Get the tags that are currently attached to the App."""
1287
+ ...
1288
+
1289
+ async def aio(self, /, *, client: typing.Optional[modal.client.Client] = None) -> dict[str, str]:
1290
+ """Get the tags that are currently attached to the App."""
1291
+ ...
1292
+
1293
+ get_tags: __get_tags_spec[typing_extensions.Self]
1294
+
1295
+ class ___logs_spec(typing_extensions.Protocol[SUPERSELF]):
1296
+ def __call__(self, /, client: typing.Optional[modal.client.Client] = None) -> typing.Generator[str, None, None]:
1297
+ """Stream logs from the app.
1298
+
1299
+ This method is considered private and its interface may change - use at your own risk!
1300
+ """
1301
+ ...
1302
+
499
1303
  def aio(
500
1304
  self, /, client: typing.Optional[modal.client.Client] = None
501
- ) -> collections.abc.AsyncGenerator[str, None]: ...
1305
+ ) -> collections.abc.AsyncGenerator[str, None]:
1306
+ """Stream logs from the app.
1307
+
1308
+ This method is considered private and its interface may change - use at your own risk!
1309
+ """
1310
+ ...
502
1311
 
503
1312
  _logs: ___logs_spec[typing_extensions.Self]
504
1313
 
505
1314
  @classmethod
506
- def _get_container_app(cls) -> typing.Optional[App]: ...
1315
+ def _get_container_app(cls) -> typing.Optional[App]:
1316
+ """Returns the `App` running inside a container.
1317
+
1318
+ This will return `None` outside of a Modal container.
1319
+ """
1320
+ ...
1321
+
507
1322
  @classmethod
508
- def _reset_container_app(cls): ...
1323
+ def _reset_container_app(cls):
1324
+ """Only used for tests."""
1325
+ ...
509
1326
 
510
1327
  _default_image: modal.image._Image