modal 1.0.5.dev2__py3-none-any.whl → 1.0.5.dev4__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.
Files changed (50) hide show
  1. modal/_clustered_functions.pyi +13 -3
  2. modal/_functions.py +5 -4
  3. modal/_partial_function.py +1 -1
  4. modal/_runtime/container_io_manager.pyi +222 -40
  5. modal/_runtime/execution_context.pyi +60 -6
  6. modal/_tunnel.pyi +380 -12
  7. modal/app.py +4 -4
  8. modal/app.pyi +658 -48
  9. modal/cli/run.py +2 -1
  10. modal/client.pyi +224 -28
  11. modal/cloud_bucket_mount.pyi +192 -4
  12. modal/cls.py +3 -3
  13. modal/cls.pyi +442 -35
  14. modal/container_process.pyi +103 -14
  15. modal/dict.py +1 -1
  16. modal/dict.pyi +453 -51
  17. modal/environments.pyi +41 -9
  18. modal/exception.py +2 -2
  19. modal/file_io.pyi +236 -45
  20. modal/functions.pyi +545 -56
  21. modal/gpu.py +1 -1
  22. modal/image.py +1 -1
  23. modal/image.pyi +1256 -74
  24. modal/io_streams.pyi +342 -39
  25. modal/mount.pyi +261 -31
  26. modal/network_file_system.pyi +307 -26
  27. modal/object.pyi +48 -9
  28. modal/parallel_map.pyi +144 -14
  29. modal/partial_function.pyi +255 -14
  30. modal/proxy.py +1 -1
  31. modal/proxy.pyi +28 -3
  32. modal/queue.py +1 -1
  33. modal/queue.pyi +447 -30
  34. modal/runner.pyi +160 -22
  35. modal/sandbox.py +7 -7
  36. modal/sandbox.pyi +310 -50
  37. modal/schedule.py +1 -1
  38. modal/secret.py +2 -2
  39. modal/secret.pyi +164 -15
  40. modal/snapshot.pyi +25 -4
  41. modal/token_flow.pyi +28 -8
  42. modal/volume.py +1 -1
  43. modal/volume.pyi +649 -59
  44. {modal-1.0.5.dev2.dist-info → modal-1.0.5.dev4.dist-info}/METADATA +1 -1
  45. {modal-1.0.5.dev2.dist-info → modal-1.0.5.dev4.dist-info}/RECORD +50 -50
  46. modal_version/__init__.py +1 -1
  47. {modal-1.0.5.dev2.dist-info → modal-1.0.5.dev4.dist-info}/WHEEL +0 -0
  48. {modal-1.0.5.dev2.dist-info → modal-1.0.5.dev4.dist-info}/entry_points.txt +0 -0
  49. {modal-1.0.5.dev2.dist-info → modal-1.0.5.dev4.dist-info}/licenses/LICENSE +0 -0
  50. {modal-1.0.5.dev2.dist-info → modal-1.0.5.dev4.dist-info}/top_level.txt +0 -0
modal/app.pyi CHANGED
@@ -26,8 +26,14 @@ class _LocalEntrypoint:
26
26
  _info: modal._utils.function_utils.FunctionInfo
27
27
  _app: _App
28
28
 
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: ...
29
+ def __init__(self, info: modal._utils.function_utils.FunctionInfo, app: _App) -> None:
30
+ """Initialize self. See help(type(self)) for accurate signature."""
31
+ ...
32
+
33
+ def __call__(self, *args: typing.Any, **kwargs: typing.Any) -> typing.Any:
34
+ """Call self as a function."""
35
+ ...
36
+
31
37
  @property
32
38
  def info(self) -> modal._utils.function_utils.FunctionInfo: ...
33
39
  @property
@@ -69,6 +75,37 @@ class _FunctionDecoratorType:
69
75
  ) -> modal.functions.Function[P, ReturnType, ReturnType]: ...
70
76
 
71
77
  class _App:
78
+ """A Modal App is a group of functions and classes that are deployed together.
79
+
80
+ The app serves at least three purposes:
81
+
82
+ * A unit of deployment for functions and classes.
83
+ * Syncing of identities of (primarily) functions and classes across processes
84
+ (your local Python interpreter and every Modal container active in your application).
85
+ * Manage log collection for everything that happens inside your code.
86
+
87
+ **Registering functions with an app**
88
+
89
+ The most common way to explicitly register an Object with an app is through the
90
+ `@app.function()` decorator. It both registers the annotated function itself and
91
+ other passed objects, like schedules and secrets, with the app:
92
+
93
+ ```python
94
+ import modal
95
+
96
+ app = modal.App()
97
+
98
+ @app.function(
99
+ secrets=[modal.Secret.from_name("some_secret")],
100
+ schedule=modal.Period(days=1),
101
+ )
102
+ def foo():
103
+ pass
104
+ ```
105
+
106
+ In this example, the secret and schedule are registered with the app.
107
+ """
108
+
72
109
  _all_apps: typing.ClassVar[dict[typing.Optional[str], list[_App]]]
73
110
  _container_app: typing.ClassVar[typing.Optional[_App]]
74
111
  _name: typing.Optional[str]
@@ -93,15 +130,38 @@ class _App:
93
130
  secrets: collections.abc.Sequence[modal.secret._Secret] = [],
94
131
  volumes: dict[typing.Union[str, pathlib.PurePosixPath], modal.volume._Volume] = {},
95
132
  include_source: typing.Optional[bool] = None,
96
- ) -> None: ...
133
+ ) -> None:
134
+ """Construct a new app, optionally with default image, mounts, secrets, or volumes.
135
+
136
+ ```python notest
137
+ image = modal.Image.debian_slim().pip_install(...)
138
+ secret = modal.Secret.from_name("my-secret")
139
+ volume = modal.Volume.from_name("my-data")
140
+ app = modal.App(image=image, secrets=[secret], volumes={"/mnt/data": volume})
141
+ ```
142
+ """
143
+ ...
144
+
97
145
  @property
98
- def name(self) -> typing.Optional[str]: ...
146
+ def name(self) -> typing.Optional[str]:
147
+ """The user-provided name of the App."""
148
+ ...
149
+
99
150
  @property
100
- def is_interactive(self) -> bool: ...
151
+ def is_interactive(self) -> bool:
152
+ """Whether the current app for the app is running in interactive mode."""
153
+ ...
154
+
101
155
  @property
102
- def app_id(self) -> typing.Optional[str]: ...
156
+ def app_id(self) -> typing.Optional[str]:
157
+ """Return the app_id of a running or stopped app."""
158
+ ...
159
+
103
160
  @property
104
- def description(self) -> typing.Optional[str]: ...
161
+ def description(self) -> typing.Optional[str]:
162
+ """The App's `name`, if available, or a fallback descriptive identifier."""
163
+ ...
164
+
105
165
  @staticmethod
106
166
  async def lookup(
107
167
  name: str,
@@ -109,7 +169,20 @@ class _App:
109
169
  client: typing.Optional[modal.client._Client] = None,
110
170
  environment_name: typing.Optional[str] = None,
111
171
  create_if_missing: bool = False,
112
- ) -> _App: ...
172
+ ) -> _App:
173
+ """Look up an App with a given name, creating a new App if necessary.
174
+
175
+ Note that Apps created through this method will be in a deployed state,
176
+ but they will not have any associated Functions or Classes. This method
177
+ is mainly useful for creating an App to associate with a Sandbox:
178
+
179
+ ```python
180
+ app = modal.App.lookup("my-app", create_if_missing=True)
181
+ modal.Sandbox.create("echo", "hi", app=app)
182
+ ```
183
+ """
184
+ ...
185
+
113
186
  def set_description(self, description: str): ...
114
187
  def _validate_blueprint_value(self, key: str, value: typing.Any): ...
115
188
  @property
@@ -127,7 +200,47 @@ class _App:
127
200
  detach: bool = False,
128
201
  interactive: bool = False,
129
202
  environment_name: typing.Optional[str] = None,
130
- ) -> typing.AsyncContextManager[_App]: ...
203
+ ) -> typing.AsyncContextManager[_App]:
204
+ """Context manager that runs an ephemeral app on Modal.
205
+
206
+ Use this as the main entry point for your Modal application. All calls
207
+ to Modal Functions should be made within the scope of this context
208
+ manager, and they will correspond to the current App.
209
+
210
+ **Example**
211
+
212
+ ```python notest
213
+ with app.run():
214
+ some_modal_function.remote()
215
+ ```
216
+
217
+ To enable output printing (i.e., to see App logs), use `modal.enable_output()`:
218
+
219
+ ```python notest
220
+ with modal.enable_output():
221
+ with app.run():
222
+ some_modal_function.remote()
223
+ ```
224
+
225
+ Note that you should not invoke this in global scope of a file where you have
226
+ Modal Functions or Classes defined, since that would run the block when the Function
227
+ or Cls is imported in your containers as well. If you want to run it as your entrypoint,
228
+ consider protecting it:
229
+
230
+ ```python
231
+ if __name__ == "__main__":
232
+ with app.run():
233
+ some_modal_function.remote()
234
+ ```
235
+
236
+ You can then run your script with:
237
+
238
+ ```shell
239
+ python app_module.py
240
+ ```
241
+ """
242
+ ...
243
+
131
244
  async def deploy(
132
245
  self,
133
246
  *,
@@ -135,23 +248,127 @@ class _App:
135
248
  environment_name: typing.Optional[str] = None,
136
249
  tag: str = "",
137
250
  client: typing.Optional[modal.client._Client] = None,
138
- ) -> typing_extensions.Self: ...
251
+ ) -> typing_extensions.Self:
252
+ """Deploy the App so that it is available persistently.
253
+
254
+ Deployed Apps will be avaible for lookup or web-based invocations until they are stopped.
255
+ Unlike with `App.run`, this method will return as soon as the deployment completes.
256
+
257
+ This method is a programmatic alternative to the `modal deploy` CLI command.
258
+
259
+ Examples:
260
+
261
+ ```python notest
262
+ app = App("my-app")
263
+ app.deploy()
264
+ ```
265
+
266
+ To enable output printing (i.e., to see build logs), use `modal.enable_output()`:
267
+
268
+ ```python notest
269
+ app = App("my-app")
270
+ with modal.enable_output():
271
+ app.deploy()
272
+ ```
273
+
274
+ Unlike with `App.run`, Function logs will not stream back to the local client after the
275
+ App is deployed.
276
+
277
+ Note that you should not invoke this method in global scope, as that would redeploy
278
+ the App every time the file is imported. If you want to write a programmatic deployment
279
+ script, protect this call so that it only runs when the file is executed directly:
280
+
281
+ ```python notest
282
+ if __name__ == "__main__":
283
+ with modal.enable_output():
284
+ app.deploy()
285
+ ```
286
+
287
+ Then you can deploy your app with:
288
+
289
+ ```shell
290
+ python app_module.py
291
+ ```
292
+ """
293
+ ...
294
+
139
295
  def _get_default_image(self): ...
140
296
  def _get_watch_mounts(self): ...
141
297
  def _add_function(self, function: modal._functions._Function, is_web_endpoint: bool): ...
142
298
  def _add_class(self, tag: str, cls: modal.cls._Cls): ...
143
299
  def _init_container(self, client: modal.client._Client, running_app: modal.running_app.RunningApp): ...
144
300
  @property
145
- def registered_functions(self) -> dict[str, modal._functions._Function]: ...
301
+ def registered_functions(self) -> dict[str, modal._functions._Function]:
302
+ """All modal.Function objects registered on the app."""
303
+ ...
304
+
146
305
  @property
147
- def registered_classes(self) -> dict[str, modal.cls._Cls]: ...
306
+ def registered_classes(self) -> dict[str, modal.cls._Cls]:
307
+ """All modal.Cls objects registered on the app."""
308
+ ...
309
+
148
310
  @property
149
- def registered_entrypoints(self) -> dict[str, _LocalEntrypoint]: ...
311
+ def registered_entrypoints(self) -> dict[str, _LocalEntrypoint]:
312
+ """All local CLI entrypoints registered on the app."""
313
+ ...
314
+
150
315
  @property
151
- def registered_web_endpoints(self) -> list[str]: ...
316
+ def registered_web_endpoints(self) -> list[str]:
317
+ """Names of web endpoint (ie. webhook) functions registered on the app."""
318
+ ...
319
+
152
320
  def local_entrypoint(
153
321
  self, _warn_parentheses_missing: typing.Any = None, *, name: typing.Optional[str] = None
154
- ) -> collections.abc.Callable[[collections.abc.Callable[..., typing.Any]], _LocalEntrypoint]: ...
322
+ ) -> collections.abc.Callable[[collections.abc.Callable[..., typing.Any]], _LocalEntrypoint]:
323
+ """Decorate a function to be used as a CLI entrypoint for a Modal App.
324
+
325
+ These functions can be used to define code that runs locally to set up the app,
326
+ and act as an entrypoint to start Modal functions from. Note that regular
327
+ Modal functions can also be used as CLI entrypoints, but unlike `local_entrypoint`,
328
+ those functions are executed remotely directly.
329
+
330
+ **Example**
331
+
332
+ ```python
333
+ @app.local_entrypoint()
334
+ def main():
335
+ some_modal_function.remote()
336
+ ```
337
+
338
+ You can call the function using `modal run` directly from the CLI:
339
+
340
+ ```shell
341
+ modal run app_module.py
342
+ ```
343
+
344
+ Note that an explicit [`app.run()`](https://modal.com/docs/reference/modal.App#run) is not needed, as an
345
+ [app](https://modal.com/docs/guide/apps) is automatically created for you.
346
+
347
+ **Multiple Entrypoints**
348
+
349
+ If you have multiple `local_entrypoint` functions, you can qualify the name of your app and function:
350
+
351
+ ```shell
352
+ modal run app_module.py::app.some_other_function
353
+ ```
354
+
355
+ **Parsing Arguments**
356
+
357
+ If your entrypoint function take arguments with primitive types, `modal run` automatically parses them as
358
+ CLI options.
359
+ For example, the following function can be called with `modal run app_module.py --foo 1 --bar "hello"`:
360
+
361
+ ```python
362
+ @app.local_entrypoint()
363
+ def main(foo: int, bar: str):
364
+ some_modal_function.call(foo, bar)
365
+ ```
366
+
367
+ Currently, `str`, `int`, `float`, `bool`, and `datetime.datetime` are supported.
368
+ Use `modal run app_module.py --help` for more information on usage.
369
+ """
370
+ ...
371
+
155
372
  def function(
156
373
  self,
157
374
  _warn_parentheses_missing: typing.Any = None,
@@ -199,7 +416,10 @@ class _App:
199
416
  allow_concurrent_inputs: typing.Optional[int] = None,
200
417
  _experimental_buffer_containers: typing.Optional[int] = None,
201
418
  allow_cross_region_volumes: typing.Optional[bool] = None,
202
- ) -> _FunctionDecoratorType: ...
419
+ ) -> _FunctionDecoratorType:
420
+ """Decorator to register a new Modal Function with this App."""
421
+ ...
422
+
203
423
  @typing_extensions.dataclass_transform(
204
424
  field_specifiers=(modal.cls.parameter,),
205
425
  kw_only_default=True,
@@ -247,19 +467,90 @@ class _App:
247
467
  allow_concurrent_inputs: typing.Optional[int] = None,
248
468
  _experimental_buffer_containers: typing.Optional[int] = None,
249
469
  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]: ...
470
+ ) -> collections.abc.Callable[[typing.Union[CLS_T, modal._partial_function._PartialFunction]], CLS_T]:
471
+ """Decorator to register a new Modal [Cls](https://modal.com/docs/reference/modal.Cls) with this App."""
472
+ ...
473
+
474
+ def include(self, /, other_app: _App) -> typing_extensions.Self:
475
+ """Include another App's objects in this one.
476
+
477
+ Useful for splitting up Modal Apps across different self-contained files.
478
+
479
+ ```python
480
+ app_a = modal.App("a")
481
+ @app.function()
482
+ def foo():
483
+ ...
484
+
485
+ app_b = modal.App("b")
486
+ @app.function()
487
+ def bar():
488
+ ...
489
+
490
+ app_a.include(app_b)
491
+
492
+ @app_a.local_entrypoint()
493
+ def main():
494
+ # use function declared on the included app
495
+ bar.remote()
496
+ ```
497
+ """
498
+ ...
499
+
500
+ def _logs(self, client: typing.Optional[modal.client._Client] = None) -> collections.abc.AsyncGenerator[str, None]:
501
+ """Stream logs from the app.
502
+
503
+ This method is considered private and its interface may change - use at your own risk!
504
+ """
505
+ ...
506
+
255
507
  @classmethod
256
- def _get_container_app(cls) -> typing.Optional[_App]: ...
508
+ def _get_container_app(cls) -> typing.Optional[_App]:
509
+ """Returns the `App` running inside a container.
510
+
511
+ This will return `None` outside of a Modal container.
512
+ """
513
+ ...
514
+
257
515
  @classmethod
258
- def _reset_container_app(cls): ...
516
+ def _reset_container_app(cls):
517
+ """Only used for tests."""
518
+ ...
259
519
 
260
520
  SUPERSELF = typing.TypeVar("SUPERSELF", covariant=True)
261
521
 
262
522
  class App:
523
+ """A Modal App is a group of functions and classes that are deployed together.
524
+
525
+ The app serves at least three purposes:
526
+
527
+ * A unit of deployment for functions and classes.
528
+ * Syncing of identities of (primarily) functions and classes across processes
529
+ (your local Python interpreter and every Modal container active in your application).
530
+ * Manage log collection for everything that happens inside your code.
531
+
532
+ **Registering functions with an app**
533
+
534
+ The most common way to explicitly register an Object with an app is through the
535
+ `@app.function()` decorator. It both registers the annotated function itself and
536
+ other passed objects, like schedules and secrets, with the app:
537
+
538
+ ```python
539
+ import modal
540
+
541
+ app = modal.App()
542
+
543
+ @app.function(
544
+ secrets=[modal.Secret.from_name("some_secret")],
545
+ schedule=modal.Period(days=1),
546
+ )
547
+ def foo():
548
+ pass
549
+ ```
550
+
551
+ In this example, the secret and schedule are registered with the app.
552
+ """
553
+
263
554
  _all_apps: typing.ClassVar[dict[typing.Optional[str], list[App]]]
264
555
  _container_app: typing.ClassVar[typing.Optional[App]]
265
556
  _name: typing.Optional[str]
@@ -284,15 +575,37 @@ class App:
284
575
  secrets: collections.abc.Sequence[modal.secret.Secret] = [],
285
576
  volumes: dict[typing.Union[str, pathlib.PurePosixPath], modal.volume.Volume] = {},
286
577
  include_source: typing.Optional[bool] = None,
287
- ) -> None: ...
578
+ ) -> None:
579
+ """Construct a new app, optionally with default image, mounts, secrets, or volumes.
580
+
581
+ ```python notest
582
+ image = modal.Image.debian_slim().pip_install(...)
583
+ secret = modal.Secret.from_name("my-secret")
584
+ volume = modal.Volume.from_name("my-data")
585
+ app = modal.App(image=image, secrets=[secret], volumes={"/mnt/data": volume})
586
+ ```
587
+ """
588
+ ...
589
+
288
590
  @property
289
- def name(self) -> typing.Optional[str]: ...
591
+ def name(self) -> typing.Optional[str]:
592
+ """The user-provided name of the App."""
593
+ ...
594
+
290
595
  @property
291
- def is_interactive(self) -> bool: ...
596
+ def is_interactive(self) -> bool:
597
+ """Whether the current app for the app is running in interactive mode."""
598
+ ...
599
+
292
600
  @property
293
- def app_id(self) -> typing.Optional[str]: ...
601
+ def app_id(self) -> typing.Optional[str]:
602
+ """Return the app_id of a running or stopped app."""
603
+ ...
604
+
294
605
  @property
295
- def description(self) -> typing.Optional[str]: ...
606
+ def description(self) -> typing.Optional[str]:
607
+ """The App's `name`, if available, or a fallback descriptive identifier."""
608
+ ...
296
609
 
297
610
  class __lookup_spec(typing_extensions.Protocol):
298
611
  def __call__(
@@ -303,7 +616,20 @@ class App:
303
616
  client: typing.Optional[modal.client.Client] = None,
304
617
  environment_name: typing.Optional[str] = None,
305
618
  create_if_missing: bool = False,
306
- ) -> App: ...
619
+ ) -> App:
620
+ """Look up an App with a given name, creating a new App if necessary.
621
+
622
+ Note that Apps created through this method will be in a deployed state,
623
+ but they will not have any associated Functions or Classes. This method
624
+ is mainly useful for creating an App to associate with a Sandbox:
625
+
626
+ ```python
627
+ app = modal.App.lookup("my-app", create_if_missing=True)
628
+ modal.Sandbox.create("echo", "hi", app=app)
629
+ ```
630
+ """
631
+ ...
632
+
307
633
  async def aio(
308
634
  self,
309
635
  /,
@@ -312,7 +638,19 @@ class App:
312
638
  client: typing.Optional[modal.client.Client] = None,
313
639
  environment_name: typing.Optional[str] = None,
314
640
  create_if_missing: bool = False,
315
- ) -> App: ...
641
+ ) -> App:
642
+ """Look up an App with a given name, creating a new App if necessary.
643
+
644
+ Note that Apps created through this method will be in a deployed state,
645
+ but they will not have any associated Functions or Classes. This method
646
+ is mainly useful for creating an App to associate with a Sandbox:
647
+
648
+ ```python
649
+ app = modal.App.lookup("my-app", create_if_missing=True)
650
+ modal.Sandbox.create("echo", "hi", app=app)
651
+ ```
652
+ """
653
+ ...
316
654
 
317
655
  lookup: __lookup_spec
318
656
 
@@ -343,7 +681,47 @@ class App:
343
681
  detach: bool = False,
344
682
  interactive: bool = False,
345
683
  environment_name: typing.Optional[str] = None,
346
- ) -> synchronicity.combined_types.AsyncAndBlockingContextManager[App]: ...
684
+ ) -> synchronicity.combined_types.AsyncAndBlockingContextManager[App]:
685
+ """Context manager that runs an ephemeral app on Modal.
686
+
687
+ Use this as the main entry point for your Modal application. All calls
688
+ to Modal Functions should be made within the scope of this context
689
+ manager, and they will correspond to the current App.
690
+
691
+ **Example**
692
+
693
+ ```python notest
694
+ with app.run():
695
+ some_modal_function.remote()
696
+ ```
697
+
698
+ To enable output printing (i.e., to see App logs), use `modal.enable_output()`:
699
+
700
+ ```python notest
701
+ with modal.enable_output():
702
+ with app.run():
703
+ some_modal_function.remote()
704
+ ```
705
+
706
+ Note that you should not invoke this in global scope of a file where you have
707
+ Modal Functions or Classes defined, since that would run the block when the Function
708
+ or Cls is imported in your containers as well. If you want to run it as your entrypoint,
709
+ consider protecting it:
710
+
711
+ ```python
712
+ if __name__ == "__main__":
713
+ with app.run():
714
+ some_modal_function.remote()
715
+ ```
716
+
717
+ You can then run your script with:
718
+
719
+ ```shell
720
+ python app_module.py
721
+ ```
722
+ """
723
+ ...
724
+
347
725
  def aio(
348
726
  self,
349
727
  /,
@@ -352,7 +730,46 @@ class App:
352
730
  detach: bool = False,
353
731
  interactive: bool = False,
354
732
  environment_name: typing.Optional[str] = None,
355
- ) -> typing.AsyncContextManager[App]: ...
733
+ ) -> typing.AsyncContextManager[App]:
734
+ """Context manager that runs an ephemeral app on Modal.
735
+
736
+ Use this as the main entry point for your Modal application. All calls
737
+ to Modal Functions should be made within the scope of this context
738
+ manager, and they will correspond to the current App.
739
+
740
+ **Example**
741
+
742
+ ```python notest
743
+ with app.run():
744
+ some_modal_function.remote()
745
+ ```
746
+
747
+ To enable output printing (i.e., to see App logs), use `modal.enable_output()`:
748
+
749
+ ```python notest
750
+ with modal.enable_output():
751
+ with app.run():
752
+ some_modal_function.remote()
753
+ ```
754
+
755
+ Note that you should not invoke this in global scope of a file where you have
756
+ Modal Functions or Classes defined, since that would run the block when the Function
757
+ or Cls is imported in your containers as well. If you want to run it as your entrypoint,
758
+ consider protecting it:
759
+
760
+ ```python
761
+ if __name__ == "__main__":
762
+ with app.run():
763
+ some_modal_function.remote()
764
+ ```
765
+
766
+ You can then run your script with:
767
+
768
+ ```shell
769
+ python app_module.py
770
+ ```
771
+ """
772
+ ...
356
773
 
357
774
  run: __run_spec[typing_extensions.Self]
358
775
 
@@ -365,7 +782,50 @@ class App:
365
782
  environment_name: typing.Optional[str] = None,
366
783
  tag: str = "",
367
784
  client: typing.Optional[modal.client.Client] = None,
368
- ) -> SUPERSELF: ...
785
+ ) -> SUPERSELF:
786
+ """Deploy the App so that it is available persistently.
787
+
788
+ Deployed Apps will be avaible for lookup or web-based invocations until they are stopped.
789
+ Unlike with `App.run`, this method will return as soon as the deployment completes.
790
+
791
+ This method is a programmatic alternative to the `modal deploy` CLI command.
792
+
793
+ Examples:
794
+
795
+ ```python notest
796
+ app = App("my-app")
797
+ app.deploy()
798
+ ```
799
+
800
+ To enable output printing (i.e., to see build logs), use `modal.enable_output()`:
801
+
802
+ ```python notest
803
+ app = App("my-app")
804
+ with modal.enable_output():
805
+ app.deploy()
806
+ ```
807
+
808
+ Unlike with `App.run`, Function logs will not stream back to the local client after the
809
+ App is deployed.
810
+
811
+ Note that you should not invoke this method in global scope, as that would redeploy
812
+ the App every time the file is imported. If you want to write a programmatic deployment
813
+ script, protect this call so that it only runs when the file is executed directly:
814
+
815
+ ```python notest
816
+ if __name__ == "__main__":
817
+ with modal.enable_output():
818
+ app.deploy()
819
+ ```
820
+
821
+ Then you can deploy your app with:
822
+
823
+ ```shell
824
+ python app_module.py
825
+ ```
826
+ """
827
+ ...
828
+
369
829
  async def aio(
370
830
  self,
371
831
  /,
@@ -374,7 +834,49 @@ class App:
374
834
  environment_name: typing.Optional[str] = None,
375
835
  tag: str = "",
376
836
  client: typing.Optional[modal.client.Client] = None,
377
- ) -> SUPERSELF: ...
837
+ ) -> SUPERSELF:
838
+ """Deploy the App so that it is available persistently.
839
+
840
+ Deployed Apps will be avaible for lookup or web-based invocations until they are stopped.
841
+ Unlike with `App.run`, this method will return as soon as the deployment completes.
842
+
843
+ This method is a programmatic alternative to the `modal deploy` CLI command.
844
+
845
+ Examples:
846
+
847
+ ```python notest
848
+ app = App("my-app")
849
+ app.deploy()
850
+ ```
851
+
852
+ To enable output printing (i.e., to see build logs), use `modal.enable_output()`:
853
+
854
+ ```python notest
855
+ app = App("my-app")
856
+ with modal.enable_output():
857
+ app.deploy()
858
+ ```
859
+
860
+ Unlike with `App.run`, Function logs will not stream back to the local client after the
861
+ App is deployed.
862
+
863
+ Note that you should not invoke this method in global scope, as that would redeploy
864
+ the App every time the file is imported. If you want to write a programmatic deployment
865
+ script, protect this call so that it only runs when the file is executed directly:
866
+
867
+ ```python notest
868
+ if __name__ == "__main__":
869
+ with modal.enable_output():
870
+ app.deploy()
871
+ ```
872
+
873
+ Then you can deploy your app with:
874
+
875
+ ```shell
876
+ python app_module.py
877
+ ```
878
+ """
879
+ ...
378
880
 
379
881
  deploy: __deploy_spec[typing_extensions.Self]
380
882
 
@@ -384,16 +886,77 @@ class App:
384
886
  def _add_class(self, tag: str, cls: modal.cls.Cls): ...
385
887
  def _init_container(self, client: modal.client.Client, running_app: modal.running_app.RunningApp): ...
386
888
  @property
387
- def registered_functions(self) -> dict[str, modal.functions.Function]: ...
889
+ def registered_functions(self) -> dict[str, modal.functions.Function]:
890
+ """All modal.Function objects registered on the app."""
891
+ ...
892
+
388
893
  @property
389
- def registered_classes(self) -> dict[str, modal.cls.Cls]: ...
894
+ def registered_classes(self) -> dict[str, modal.cls.Cls]:
895
+ """All modal.Cls objects registered on the app."""
896
+ ...
897
+
390
898
  @property
391
- def registered_entrypoints(self) -> dict[str, LocalEntrypoint]: ...
899
+ def registered_entrypoints(self) -> dict[str, LocalEntrypoint]:
900
+ """All local CLI entrypoints registered on the app."""
901
+ ...
902
+
392
903
  @property
393
- def registered_web_endpoints(self) -> list[str]: ...
904
+ def registered_web_endpoints(self) -> list[str]:
905
+ """Names of web endpoint (ie. webhook) functions registered on the app."""
906
+ ...
907
+
394
908
  def local_entrypoint(
395
909
  self, _warn_parentheses_missing: typing.Any = None, *, name: typing.Optional[str] = None
396
- ) -> collections.abc.Callable[[collections.abc.Callable[..., typing.Any]], LocalEntrypoint]: ...
910
+ ) -> collections.abc.Callable[[collections.abc.Callable[..., typing.Any]], LocalEntrypoint]:
911
+ """Decorate a function to be used as a CLI entrypoint for a Modal App.
912
+
913
+ These functions can be used to define code that runs locally to set up the app,
914
+ and act as an entrypoint to start Modal functions from. Note that regular
915
+ Modal functions can also be used as CLI entrypoints, but unlike `local_entrypoint`,
916
+ those functions are executed remotely directly.
917
+
918
+ **Example**
919
+
920
+ ```python
921
+ @app.local_entrypoint()
922
+ def main():
923
+ some_modal_function.remote()
924
+ ```
925
+
926
+ You can call the function using `modal run` directly from the CLI:
927
+
928
+ ```shell
929
+ modal run app_module.py
930
+ ```
931
+
932
+ Note that an explicit [`app.run()`](https://modal.com/docs/reference/modal.App#run) is not needed, as an
933
+ [app](https://modal.com/docs/guide/apps) is automatically created for you.
934
+
935
+ **Multiple Entrypoints**
936
+
937
+ If you have multiple `local_entrypoint` functions, you can qualify the name of your app and function:
938
+
939
+ ```shell
940
+ modal run app_module.py::app.some_other_function
941
+ ```
942
+
943
+ **Parsing Arguments**
944
+
945
+ If your entrypoint function take arguments with primitive types, `modal run` automatically parses them as
946
+ CLI options.
947
+ For example, the following function can be called with `modal run app_module.py --foo 1 --bar "hello"`:
948
+
949
+ ```python
950
+ @app.local_entrypoint()
951
+ def main(foo: int, bar: str):
952
+ some_modal_function.call(foo, bar)
953
+ ```
954
+
955
+ Currently, `str`, `int`, `float`, `bool`, and `datetime.datetime` are supported.
956
+ Use `modal run app_module.py --help` for more information on usage.
957
+ """
958
+ ...
959
+
397
960
  def function(
398
961
  self,
399
962
  _warn_parentheses_missing: typing.Any = None,
@@ -441,7 +1004,10 @@ class App:
441
1004
  allow_concurrent_inputs: typing.Optional[int] = None,
442
1005
  _experimental_buffer_containers: typing.Optional[int] = None,
443
1006
  allow_cross_region_volumes: typing.Optional[bool] = None,
444
- ) -> _FunctionDecoratorType: ...
1007
+ ) -> _FunctionDecoratorType:
1008
+ """Decorator to register a new Modal Function with this App."""
1009
+ ...
1010
+
445
1011
  @typing_extensions.dataclass_transform(
446
1012
  field_specifiers=(modal.cls.parameter,),
447
1013
  kw_only_default=True,
@@ -489,22 +1055,66 @@ class App:
489
1055
  allow_concurrent_inputs: typing.Optional[int] = None,
490
1056
  _experimental_buffer_containers: typing.Optional[int] = None,
491
1057
  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: ...
1058
+ ) -> collections.abc.Callable[[typing.Union[CLS_T, modal.partial_function.PartialFunction]], CLS_T]:
1059
+ """Decorator to register a new Modal [Cls](https://modal.com/docs/reference/modal.Cls) with this App."""
1060
+ ...
1061
+
1062
+ def include(self, /, other_app: App) -> typing_extensions.Self:
1063
+ """Include another App's objects in this one.
1064
+
1065
+ Useful for splitting up Modal Apps across different self-contained files.
1066
+
1067
+ ```python
1068
+ app_a = modal.App("a")
1069
+ @app.function()
1070
+ def foo():
1071
+ ...
1072
+
1073
+ app_b = modal.App("b")
1074
+ @app.function()
1075
+ def bar():
1076
+ ...
1077
+
1078
+ app_a.include(app_b)
1079
+
1080
+ @app_a.local_entrypoint()
1081
+ def main():
1082
+ # use function declared on the included app
1083
+ bar.remote()
1084
+ ```
1085
+ """
1086
+ ...
494
1087
 
495
1088
  class ___logs_spec(typing_extensions.Protocol[SUPERSELF]):
496
- def __call__(
497
- self, /, client: typing.Optional[modal.client.Client] = None
498
- ) -> typing.Generator[str, None, None]: ...
1089
+ def __call__(self, /, client: typing.Optional[modal.client.Client] = None) -> typing.Generator[str, None, None]:
1090
+ """Stream logs from the app.
1091
+
1092
+ This method is considered private and its interface may change - use at your own risk!
1093
+ """
1094
+ ...
1095
+
499
1096
  def aio(
500
1097
  self, /, client: typing.Optional[modal.client.Client] = None
501
- ) -> collections.abc.AsyncGenerator[str, None]: ...
1098
+ ) -> collections.abc.AsyncGenerator[str, None]:
1099
+ """Stream logs from the app.
1100
+
1101
+ This method is considered private and its interface may change - use at your own risk!
1102
+ """
1103
+ ...
502
1104
 
503
1105
  _logs: ___logs_spec[typing_extensions.Self]
504
1106
 
505
1107
  @classmethod
506
- def _get_container_app(cls) -> typing.Optional[App]: ...
1108
+ def _get_container_app(cls) -> typing.Optional[App]:
1109
+ """Returns the `App` running inside a container.
1110
+
1111
+ This will return `None` outside of a Modal container.
1112
+ """
1113
+ ...
1114
+
507
1115
  @classmethod
508
- def _reset_container_app(cls): ...
1116
+ def _reset_container_app(cls):
1117
+ """Only used for tests."""
1118
+ ...
509
1119
 
510
1120
  _default_image: modal.image._Image