modal 1.0.6.dev58__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 (147) hide show
  1. modal/__main__.py +3 -4
  2. modal/_billing.py +80 -0
  3. modal/_clustered_functions.py +7 -3
  4. modal/_clustered_functions.pyi +4 -2
  5. modal/_container_entrypoint.py +41 -49
  6. modal/_functions.py +424 -195
  7. modal/_grpc_client.py +171 -0
  8. modal/_load_context.py +105 -0
  9. modal/_object.py +68 -20
  10. modal/_output.py +58 -45
  11. modal/_partial_function.py +36 -11
  12. modal/_pty.py +7 -3
  13. modal/_resolver.py +21 -35
  14. modal/_runtime/asgi.py +4 -3
  15. modal/_runtime/container_io_manager.py +301 -186
  16. modal/_runtime/container_io_manager.pyi +70 -61
  17. modal/_runtime/execution_context.py +18 -2
  18. modal/_runtime/execution_context.pyi +4 -1
  19. modal/_runtime/gpu_memory_snapshot.py +170 -63
  20. modal/_runtime/user_code_imports.py +28 -58
  21. modal/_serialization.py +57 -1
  22. modal/_utils/async_utils.py +33 -12
  23. modal/_utils/auth_token_manager.py +2 -5
  24. modal/_utils/blob_utils.py +110 -53
  25. modal/_utils/function_utils.py +49 -42
  26. modal/_utils/grpc_utils.py +80 -50
  27. modal/_utils/mount_utils.py +26 -1
  28. modal/_utils/name_utils.py +17 -3
  29. modal/_utils/task_command_router_client.py +536 -0
  30. modal/_utils/time_utils.py +34 -6
  31. modal/app.py +219 -83
  32. modal/app.pyi +229 -56
  33. modal/billing.py +5 -0
  34. modal/{requirements → builder}/2025.06.txt +1 -0
  35. modal/{requirements → builder}/PREVIEW.txt +1 -0
  36. modal/cli/_download.py +19 -3
  37. modal/cli/_traceback.py +3 -2
  38. modal/cli/app.py +4 -4
  39. modal/cli/cluster.py +15 -7
  40. modal/cli/config.py +5 -3
  41. modal/cli/container.py +7 -6
  42. modal/cli/dict.py +22 -16
  43. modal/cli/entry_point.py +12 -5
  44. modal/cli/environment.py +5 -4
  45. modal/cli/import_refs.py +3 -3
  46. modal/cli/launch.py +102 -5
  47. modal/cli/network_file_system.py +9 -13
  48. modal/cli/profile.py +3 -2
  49. modal/cli/programs/launch_instance_ssh.py +94 -0
  50. modal/cli/programs/run_jupyter.py +1 -1
  51. modal/cli/programs/run_marimo.py +95 -0
  52. modal/cli/programs/vscode.py +1 -1
  53. modal/cli/queues.py +57 -26
  54. modal/cli/run.py +58 -16
  55. modal/cli/secret.py +48 -22
  56. modal/cli/utils.py +3 -4
  57. modal/cli/volume.py +28 -25
  58. modal/client.py +13 -116
  59. modal/client.pyi +9 -91
  60. modal/cloud_bucket_mount.py +5 -3
  61. modal/cloud_bucket_mount.pyi +5 -1
  62. modal/cls.py +130 -102
  63. modal/cls.pyi +45 -85
  64. modal/config.py +29 -10
  65. modal/container_process.py +291 -13
  66. modal/container_process.pyi +95 -32
  67. modal/dict.py +282 -63
  68. modal/dict.pyi +423 -73
  69. modal/environments.py +15 -27
  70. modal/environments.pyi +5 -15
  71. modal/exception.py +8 -0
  72. modal/experimental/__init__.py +143 -38
  73. modal/experimental/flash.py +247 -78
  74. modal/experimental/flash.pyi +137 -9
  75. modal/file_io.py +14 -28
  76. modal/file_io.pyi +2 -2
  77. modal/file_pattern_matcher.py +25 -16
  78. modal/functions.pyi +134 -61
  79. modal/image.py +255 -86
  80. modal/image.pyi +300 -62
  81. modal/io_streams.py +436 -126
  82. modal/io_streams.pyi +236 -171
  83. modal/mount.py +62 -157
  84. modal/mount.pyi +45 -172
  85. modal/network_file_system.py +30 -53
  86. modal/network_file_system.pyi +16 -76
  87. modal/object.pyi +42 -8
  88. modal/parallel_map.py +821 -113
  89. modal/parallel_map.pyi +134 -0
  90. modal/partial_function.pyi +4 -1
  91. modal/proxy.py +16 -7
  92. modal/proxy.pyi +10 -2
  93. modal/queue.py +263 -61
  94. modal/queue.pyi +409 -66
  95. modal/runner.py +112 -92
  96. modal/runner.pyi +45 -27
  97. modal/sandbox.py +451 -124
  98. modal/sandbox.pyi +513 -67
  99. modal/secret.py +291 -67
  100. modal/secret.pyi +425 -19
  101. modal/serving.py +7 -11
  102. modal/serving.pyi +7 -8
  103. modal/snapshot.py +11 -8
  104. modal/token_flow.py +4 -4
  105. modal/volume.py +344 -98
  106. modal/volume.pyi +464 -68
  107. {modal-1.0.6.dev58.dist-info → modal-1.2.3.dev7.dist-info}/METADATA +9 -8
  108. modal-1.2.3.dev7.dist-info/RECORD +195 -0
  109. modal_docs/mdmd/mdmd.py +11 -1
  110. modal_proto/api.proto +399 -67
  111. modal_proto/api_grpc.py +241 -1
  112. modal_proto/api_pb2.py +1395 -1000
  113. modal_proto/api_pb2.pyi +1239 -79
  114. modal_proto/api_pb2_grpc.py +499 -4
  115. modal_proto/api_pb2_grpc.pyi +162 -14
  116. modal_proto/modal_api_grpc.py +175 -160
  117. modal_proto/sandbox_router.proto +145 -0
  118. modal_proto/sandbox_router_grpc.py +105 -0
  119. modal_proto/sandbox_router_pb2.py +149 -0
  120. modal_proto/sandbox_router_pb2.pyi +333 -0
  121. modal_proto/sandbox_router_pb2_grpc.py +203 -0
  122. modal_proto/sandbox_router_pb2_grpc.pyi +75 -0
  123. modal_proto/task_command_router.proto +144 -0
  124. modal_proto/task_command_router_grpc.py +105 -0
  125. modal_proto/task_command_router_pb2.py +149 -0
  126. modal_proto/task_command_router_pb2.pyi +333 -0
  127. modal_proto/task_command_router_pb2_grpc.py +203 -0
  128. modal_proto/task_command_router_pb2_grpc.pyi +75 -0
  129. modal_version/__init__.py +1 -1
  130. modal-1.0.6.dev58.dist-info/RECORD +0 -183
  131. modal_proto/modal_options_grpc.py +0 -3
  132. modal_proto/options.proto +0 -19
  133. modal_proto/options_grpc.py +0 -3
  134. modal_proto/options_pb2.py +0 -35
  135. modal_proto/options_pb2.pyi +0 -20
  136. modal_proto/options_pb2_grpc.py +0 -4
  137. modal_proto/options_pb2_grpc.pyi +0 -7
  138. /modal/{requirements → builder}/2023.12.312.txt +0 -0
  139. /modal/{requirements → builder}/2023.12.txt +0 -0
  140. /modal/{requirements → builder}/2024.04.txt +0 -0
  141. /modal/{requirements → builder}/2024.10.txt +0 -0
  142. /modal/{requirements → builder}/README.md +0 -0
  143. /modal/{requirements → builder}/base-images.json +0 -0
  144. {modal-1.0.6.dev58.dist-info → modal-1.2.3.dev7.dist-info}/WHEEL +0 -0
  145. {modal-1.0.6.dev58.dist-info → modal-1.2.3.dev7.dist-info}/entry_points.txt +0 -0
  146. {modal-1.0.6.dev58.dist-info → modal-1.2.3.dev7.dist-info}/licenses/LICENSE +0 -0
  147. {modal-1.0.6.dev58.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
@@ -66,9 +67,10 @@ class Function(
66
67
  @staticmethod
67
68
  def from_local(
68
69
  info: modal._utils.function_utils.FunctionInfo,
69
- app,
70
+ app: typing.Optional[modal.app.App],
70
71
  image: modal.image.Image,
71
- 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,
72
74
  schedule: typing.Optional[modal.schedule.Schedule] = None,
73
75
  is_generator: bool = False,
74
76
  gpu: typing.Union[None, str, modal.gpu._GPUConfig, list[typing.Union[None, str, modal.gpu._GPUConfig]]] = None,
@@ -84,7 +86,8 @@ class Function(
84
86
  memory: typing.Union[int, tuple[int, int], None] = None,
85
87
  proxy: typing.Optional[modal.proxy.Proxy] = None,
86
88
  retries: typing.Union[int, modal.retries.Retries, None] = None,
87
- timeout: typing.Optional[int] = None,
89
+ timeout: int = 300,
90
+ startup_timeout: typing.Optional[int] = None,
88
91
  min_containers: typing.Optional[int] = None,
89
92
  max_containers: typing.Optional[int] = None,
90
93
  buffer_containers: typing.Optional[int] = None,
@@ -105,13 +108,16 @@ class Function(
105
108
  rdma: typing.Optional[bool] = None,
106
109
  max_inputs: typing.Optional[int] = None,
107
110
  ephemeral_disk: typing.Optional[int] = None,
108
- include_source: typing.Optional[bool] = None,
111
+ include_source: bool = True,
109
112
  experimental_options: typing.Optional[dict[str, str]] = None,
110
113
  _experimental_proxy_ip: typing.Optional[str] = None,
111
114
  _experimental_custom_scaling_factor: typing.Optional[float] = None,
112
- _experimental_enable_gpu_snapshot: bool = False,
115
+ restrict_output: bool = False,
113
116
  ) -> Function:
114
- """mdmd:hidden"""
117
+ """mdmd:hidden
118
+
119
+ Note: This is not intended to be public API.
120
+ """
115
121
  ...
116
122
 
117
123
  def _bind_parameters(
@@ -240,10 +246,16 @@ class Function(
240
246
  keep_warm: __keep_warm_spec[typing_extensions.Self]
241
247
 
242
248
  @classmethod
243
- def _from_name(cls, app_name: str, name: str, namespace=None, environment_name: typing.Optional[str] = None): ...
249
+ def _from_name(cls, app_name: str, name: str, *, load_context_overrides: modal._load_context.LoadContext): ...
244
250
  @classmethod
245
251
  def from_name(
246
- cls: type[Function], app_name: str, name: str, *, namespace=None, environment_name: typing.Optional[str] = None
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,
247
259
  ) -> Function:
248
260
  """Reference a Function from a deployed App by its name.
249
261
 
@@ -257,55 +269,6 @@ class Function(
257
269
  """
258
270
  ...
259
271
 
260
- class __lookup_spec(typing_extensions.Protocol):
261
- def __call__(
262
- self,
263
- /,
264
- app_name: str,
265
- name: str,
266
- namespace=None,
267
- client: typing.Optional[modal.client.Client] = None,
268
- environment_name: typing.Optional[str] = None,
269
- ) -> Function:
270
- """mdmd:hidden
271
- Lookup a Function from a deployed App by its name.
272
-
273
- DEPRECATED: This method is deprecated in favor of `modal.Function.from_name`.
274
-
275
- In contrast to `modal.Function.from_name`, this is an eager method
276
- that will hydrate the local object with metadata from Modal servers.
277
-
278
- ```python notest
279
- f = modal.Function.lookup("other-app", "function")
280
- ```
281
- """
282
- ...
283
-
284
- async def aio(
285
- self,
286
- /,
287
- app_name: str,
288
- name: str,
289
- namespace=None,
290
- client: typing.Optional[modal.client.Client] = None,
291
- environment_name: typing.Optional[str] = None,
292
- ) -> Function:
293
- """mdmd:hidden
294
- Lookup a Function from a deployed App by its name.
295
-
296
- DEPRECATED: This method is deprecated in favor of `modal.Function.from_name`.
297
-
298
- In contrast to `modal.Function.from_name`, this is an eager method
299
- that will hydrate the local object with metadata from Modal servers.
300
-
301
- ```python notest
302
- f = modal.Function.lookup("other-app", "function")
303
- ```
304
- """
305
- ...
306
-
307
- lookup: __lookup_spec
308
-
309
272
  @property
310
273
  def tag(self) -> str:
311
274
  """mdmd:hidden"""
@@ -360,6 +323,17 @@ class Function(
360
323
 
361
324
  get_web_url: __get_web_url_spec[typing_extensions.Self]
362
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
+
363
337
  @property
364
338
  def is_generator(self) -> bool:
365
339
  """mdmd:hidden"""
@@ -406,6 +380,12 @@ class Function(
406
380
 
407
381
  _map: ___map_spec[typing_extensions.Self]
408
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
+
409
389
  class ___call_function_spec(typing_extensions.Protocol[ReturnType_INNER, SUPERSELF]):
410
390
  def __call__(self, /, args, kwargs) -> ReturnType_INNER: ...
411
391
  async def aio(self, /, args, kwargs) -> ReturnType_INNER: ...
@@ -694,6 +674,34 @@ class Function(
694
674
 
695
675
  spawn_map: __spawn_map_spec[typing_extensions.Self]
696
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
+
697
705
  class FunctionCall(typing.Generic[modal._functions.ReturnType], modal.object.Object):
698
706
  """A reference to an executed function call.
699
707
 
@@ -706,6 +714,7 @@ class FunctionCall(typing.Generic[modal._functions.ReturnType], modal.object.Obj
706
714
  """
707
715
 
708
716
  _is_generator: bool
717
+ _num_inputs: typing.Optional[int]
709
718
 
710
719
  def __init__(self, *args, **kwargs):
711
720
  """mdmd:hidden"""
@@ -713,9 +722,22 @@ class FunctionCall(typing.Generic[modal._functions.ReturnType], modal.object.Obj
713
722
 
714
723
  def _invocation(self): ...
715
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
+
716
736
  class __get_spec(typing_extensions.Protocol[ReturnType_INNER, SUPERSELF]):
717
- def __call__(self, /, timeout: typing.Optional[float] = None) -> ReturnType_INNER:
718
- """Get the result of the function call.
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()`.
719
741
 
720
742
  This function waits indefinitely by default. It takes an optional
721
743
  `timeout` argument that specifies the maximum number of seconds to wait,
@@ -725,8 +747,10 @@ class FunctionCall(typing.Generic[modal._functions.ReturnType], modal.object.Obj
725
747
  """
726
748
  ...
727
749
 
728
- async def aio(self, /, timeout: typing.Optional[float] = None) -> ReturnType_INNER:
729
- """Get the result of the function call.
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()`.
730
754
 
731
755
  This function waits indefinitely by default. It takes an optional
732
756
  `timeout` argument that specifies the maximum number of seconds to wait,
@@ -738,6 +762,55 @@ class FunctionCall(typing.Generic[modal._functions.ReturnType], modal.object.Obj
738
762
 
739
763
  get: __get_spec[modal._functions.ReturnType, typing_extensions.Self]
740
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
+
741
814
  class __get_call_graph_spec(typing_extensions.Protocol[SUPERSELF]):
742
815
  def __call__(self, /) -> list[modal.call_graph.InputInfo]:
743
816
  """Returns a structure representing the call graph from a given root