modal 1.1.5.dev83__py3-none-any.whl → 1.3.1.dev8__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 (139) hide show
  1. modal/__init__.py +4 -4
  2. modal/__main__.py +4 -29
  3. modal/_billing.py +84 -0
  4. modal/_clustered_functions.py +1 -3
  5. modal/_container_entrypoint.py +33 -208
  6. modal/_functions.py +146 -121
  7. modal/_grpc_client.py +191 -0
  8. modal/_ipython.py +16 -6
  9. modal/_load_context.py +106 -0
  10. modal/_object.py +72 -21
  11. modal/_output.py +12 -14
  12. modal/_partial_function.py +31 -4
  13. modal/_resolver.py +44 -57
  14. modal/_runtime/container_io_manager.py +26 -28
  15. modal/_runtime/container_io_manager.pyi +42 -44
  16. modal/_runtime/gpu_memory_snapshot.py +9 -7
  17. modal/_runtime/user_code_event_loop.py +80 -0
  18. modal/_runtime/user_code_imports.py +236 -10
  19. modal/_serialization.py +2 -1
  20. modal/_traceback.py +4 -13
  21. modal/_tunnel.py +16 -11
  22. modal/_tunnel.pyi +25 -3
  23. modal/_utils/async_utils.py +337 -10
  24. modal/_utils/auth_token_manager.py +1 -4
  25. modal/_utils/blob_utils.py +29 -22
  26. modal/_utils/function_utils.py +20 -21
  27. modal/_utils/grpc_testing.py +6 -3
  28. modal/_utils/grpc_utils.py +223 -64
  29. modal/_utils/mount_utils.py +26 -1
  30. modal/_utils/package_utils.py +0 -1
  31. modal/_utils/rand_pb_testing.py +8 -1
  32. modal/_utils/task_command_router_client.py +524 -0
  33. modal/_vendor/cloudpickle.py +144 -48
  34. modal/app.py +215 -96
  35. modal/app.pyi +78 -37
  36. modal/billing.py +5 -0
  37. modal/builder/2025.06.txt +6 -3
  38. modal/builder/PREVIEW.txt +2 -1
  39. modal/builder/base-images.json +4 -2
  40. modal/cli/_download.py +19 -3
  41. modal/cli/cluster.py +4 -2
  42. modal/cli/config.py +3 -1
  43. modal/cli/container.py +5 -4
  44. modal/cli/dict.py +5 -2
  45. modal/cli/entry_point.py +26 -2
  46. modal/cli/environment.py +2 -16
  47. modal/cli/launch.py +1 -76
  48. modal/cli/network_file_system.py +5 -20
  49. modal/cli/queues.py +5 -4
  50. modal/cli/run.py +24 -204
  51. modal/cli/secret.py +1 -2
  52. modal/cli/shell.py +375 -0
  53. modal/cli/utils.py +1 -13
  54. modal/cli/volume.py +11 -17
  55. modal/client.py +16 -125
  56. modal/client.pyi +94 -144
  57. modal/cloud_bucket_mount.py +3 -1
  58. modal/cloud_bucket_mount.pyi +4 -0
  59. modal/cls.py +101 -64
  60. modal/cls.pyi +9 -8
  61. modal/config.py +21 -1
  62. modal/container_process.py +288 -12
  63. modal/container_process.pyi +99 -38
  64. modal/dict.py +72 -33
  65. modal/dict.pyi +88 -57
  66. modal/environments.py +16 -8
  67. modal/environments.pyi +6 -2
  68. modal/exception.py +154 -16
  69. modal/experimental/__init__.py +23 -5
  70. modal/experimental/flash.py +161 -74
  71. modal/experimental/flash.pyi +97 -49
  72. modal/file_io.py +50 -92
  73. modal/file_io.pyi +117 -89
  74. modal/functions.pyi +70 -87
  75. modal/image.py +73 -47
  76. modal/image.pyi +33 -30
  77. modal/io_streams.py +500 -149
  78. modal/io_streams.pyi +279 -189
  79. modal/mount.py +60 -45
  80. modal/mount.pyi +41 -17
  81. modal/network_file_system.py +19 -11
  82. modal/network_file_system.pyi +72 -39
  83. modal/object.pyi +114 -22
  84. modal/parallel_map.py +42 -44
  85. modal/parallel_map.pyi +9 -17
  86. modal/partial_function.pyi +4 -2
  87. modal/proxy.py +14 -6
  88. modal/proxy.pyi +10 -2
  89. modal/queue.py +45 -38
  90. modal/queue.pyi +88 -52
  91. modal/runner.py +96 -96
  92. modal/runner.pyi +44 -27
  93. modal/sandbox.py +225 -108
  94. modal/sandbox.pyi +226 -63
  95. modal/secret.py +58 -56
  96. modal/secret.pyi +28 -13
  97. modal/serving.py +7 -11
  98. modal/serving.pyi +7 -8
  99. modal/snapshot.py +29 -15
  100. modal/snapshot.pyi +18 -10
  101. modal/token_flow.py +1 -1
  102. modal/token_flow.pyi +4 -6
  103. modal/volume.py +102 -55
  104. modal/volume.pyi +125 -66
  105. {modal-1.1.5.dev83.dist-info → modal-1.3.1.dev8.dist-info}/METADATA +10 -9
  106. modal-1.3.1.dev8.dist-info/RECORD +189 -0
  107. modal_proto/api.proto +86 -30
  108. modal_proto/api_grpc.py +10 -25
  109. modal_proto/api_pb2.py +1080 -1047
  110. modal_proto/api_pb2.pyi +253 -79
  111. modal_proto/api_pb2_grpc.py +14 -48
  112. modal_proto/api_pb2_grpc.pyi +6 -18
  113. modal_proto/modal_api_grpc.py +175 -176
  114. modal_proto/{sandbox_router.proto → task_command_router.proto} +62 -45
  115. modal_proto/task_command_router_grpc.py +138 -0
  116. modal_proto/task_command_router_pb2.py +180 -0
  117. modal_proto/{sandbox_router_pb2.pyi → task_command_router_pb2.pyi} +110 -63
  118. modal_proto/task_command_router_pb2_grpc.py +272 -0
  119. modal_proto/task_command_router_pb2_grpc.pyi +100 -0
  120. modal_version/__init__.py +1 -1
  121. modal_version/__main__.py +1 -1
  122. modal/cli/programs/launch_instance_ssh.py +0 -94
  123. modal/cli/programs/run_marimo.py +0 -95
  124. modal-1.1.5.dev83.dist-info/RECORD +0 -191
  125. modal_proto/modal_options_grpc.py +0 -3
  126. modal_proto/options.proto +0 -19
  127. modal_proto/options_grpc.py +0 -3
  128. modal_proto/options_pb2.py +0 -35
  129. modal_proto/options_pb2.pyi +0 -20
  130. modal_proto/options_pb2_grpc.py +0 -4
  131. modal_proto/options_pb2_grpc.pyi +0 -7
  132. modal_proto/sandbox_router_grpc.py +0 -105
  133. modal_proto/sandbox_router_pb2.py +0 -148
  134. modal_proto/sandbox_router_pb2_grpc.py +0 -203
  135. modal_proto/sandbox_router_pb2_grpc.pyi +0 -75
  136. {modal-1.1.5.dev83.dist-info → modal-1.3.1.dev8.dist-info}/WHEEL +0 -0
  137. {modal-1.1.5.dev83.dist-info → modal-1.3.1.dev8.dist-info}/entry_points.txt +0 -0
  138. {modal-1.1.5.dev83.dist-info → modal-1.3.1.dev8.dist-info}/licenses/LICENSE +0 -0
  139. {modal-1.1.5.dev83.dist-info → modal-1.3.1.dev8.dist-info}/top_level.txt +0 -0
modal/file_io.pyi CHANGED
@@ -7,21 +7,16 @@ import typing_extensions
7
7
  T = typing.TypeVar("T")
8
8
 
9
9
  async def _delete_bytes(file: _FileIO, start: typing.Optional[int] = None, end: typing.Optional[int] = None) -> None:
10
- """Delete a range of bytes from the file.
11
-
12
- `start` and `end` are byte offsets. `start` is inclusive, `end` is exclusive.
13
- If either is None, the start or end of the file is used, respectively.
10
+ """mdmd:hidden
11
+ This method has been removed.
14
12
  """
15
13
  ...
16
14
 
17
15
  async def _replace_bytes(
18
16
  file: _FileIO, data: bytes, start: typing.Optional[int] = None, end: typing.Optional[int] = None
19
17
  ) -> None:
20
- """Replace a range of bytes in the file with new data. The length of the data does not
21
- have to be the same as the length of the range being replaced.
22
-
23
- `start` and `end` are byte offsets. `start` is inclusive, `end` is exclusive.
24
- If either is None, the start or end of the file is used, respectively.
18
+ """mdmd:hidden
19
+ This method has been removed.
25
20
  """
26
21
  ...
27
22
 
@@ -174,18 +169,14 @@ class _FileIO(typing.Generic[T]):
174
169
 
175
170
  class __delete_bytes_spec(typing_extensions.Protocol):
176
171
  def __call__(self, /, file: FileIO, start: typing.Optional[int] = None, end: typing.Optional[int] = None) -> None:
177
- """Delete a range of bytes from the file.
178
-
179
- `start` and `end` are byte offsets. `start` is inclusive, `end` is exclusive.
180
- If either is None, the start or end of the file is used, respectively.
172
+ """mdmd:hidden
173
+ This method has been removed.
181
174
  """
182
175
  ...
183
176
 
184
177
  async def aio(self, /, file: FileIO, start: typing.Optional[int] = None, end: typing.Optional[int] = None) -> None:
185
- """Delete a range of bytes from the file.
186
-
187
- `start` and `end` are byte offsets. `start` is inclusive, `end` is exclusive.
188
- If either is None, the start or end of the file is used, respectively.
178
+ """mdmd:hidden
179
+ This method has been removed.
189
180
  """
190
181
  ...
191
182
 
@@ -195,29 +186,21 @@ class __replace_bytes_spec(typing_extensions.Protocol):
195
186
  def __call__(
196
187
  self, /, file: FileIO, data: bytes, start: typing.Optional[int] = None, end: typing.Optional[int] = None
197
188
  ) -> None:
198
- """Replace a range of bytes in the file with new data. The length of the data does not
199
- have to be the same as the length of the range being replaced.
200
-
201
- `start` and `end` are byte offsets. `start` is inclusive, `end` is exclusive.
202
- If either is None, the start or end of the file is used, respectively.
189
+ """mdmd:hidden
190
+ This method has been removed.
203
191
  """
204
192
  ...
205
193
 
206
194
  async def aio(
207
195
  self, /, file: FileIO, data: bytes, start: typing.Optional[int] = None, end: typing.Optional[int] = None
208
196
  ) -> None:
209
- """Replace a range of bytes in the file with new data. The length of the data does not
210
- have to be the same as the length of the range being replaced.
211
-
212
- `start` and `end` are byte offsets. `start` is inclusive, `end` is exclusive.
213
- If either is None, the start or end of the file is used, respectively.
197
+ """mdmd:hidden
198
+ This method has been removed.
214
199
  """
215
200
  ...
216
201
 
217
202
  replace_bytes: __replace_bytes_spec
218
203
 
219
- SUPERSELF = typing.TypeVar("SUPERSELF", covariant=True)
220
-
221
204
  T_INNER = typing.TypeVar("T_INNER", covariant=True)
222
205
 
223
206
  class FileIO(typing.Generic[T]):
@@ -252,56 +235,70 @@ class FileIO(typing.Generic[T]):
252
235
  def __init__(self, client: modal.client.Client, task_id: str) -> None: ...
253
236
  def _validate_mode(self, mode: str) -> None: ...
254
237
 
255
- class ___consume_output_spec(typing_extensions.Protocol[SUPERSELF]):
238
+ class ___consume_output_spec(typing_extensions.Protocol):
256
239
  def __call__(self, /, exec_id: str) -> typing.Iterator[typing.Union[bytes, None, Exception]]: ...
257
240
  def aio(self, /, exec_id: str) -> typing.AsyncIterator[typing.Union[bytes, None, Exception]]: ...
258
241
 
259
- _consume_output: ___consume_output_spec[typing_extensions.Self]
242
+ _consume_output: ___consume_output_spec
260
243
 
261
- class ___consume_watch_output_spec(typing_extensions.Protocol[SUPERSELF]):
244
+ class ___consume_watch_output_spec(typing_extensions.Protocol):
262
245
  def __call__(self, /, exec_id: str) -> None: ...
263
246
  async def aio(self, /, exec_id: str) -> None: ...
264
247
 
265
- _consume_watch_output: ___consume_watch_output_spec[typing_extensions.Self]
248
+ _consume_watch_output: ___consume_watch_output_spec
266
249
 
267
- class ___parse_watch_output_spec(typing_extensions.Protocol[SUPERSELF]):
250
+ class ___parse_watch_output_spec(typing_extensions.Protocol):
268
251
  def __call__(self, /, event: bytes) -> typing.Optional[FileWatchEvent]: ...
269
252
  async def aio(self, /, event: bytes) -> typing.Optional[FileWatchEvent]: ...
270
253
 
271
- _parse_watch_output: ___parse_watch_output_spec[typing_extensions.Self]
254
+ _parse_watch_output: ___parse_watch_output_spec
272
255
 
273
- class ___wait_spec(typing_extensions.Protocol[SUPERSELF]):
256
+ class ___wait_spec(typing_extensions.Protocol):
274
257
  def __call__(self, /, exec_id: str) -> bytes: ...
275
258
  async def aio(self, /, exec_id: str) -> bytes: ...
276
259
 
277
- _wait: ___wait_spec[typing_extensions.Self]
260
+ _wait: ___wait_spec
278
261
 
279
262
  def _validate_type(self, data: typing.Union[bytes, str]) -> None: ...
280
263
 
281
- class ___open_file_spec(typing_extensions.Protocol[SUPERSELF]):
264
+ class ___open_file_spec(typing_extensions.Protocol):
282
265
  def __call__(self, /, path: str, mode: str) -> None: ...
283
266
  async def aio(self, /, path: str, mode: str) -> None: ...
284
267
 
285
- _open_file: ___open_file_spec[typing_extensions.Self]
268
+ _open_file: ___open_file_spec
269
+
270
+ class __create_spec(typing_extensions.Protocol):
271
+ def __call__(
272
+ self,
273
+ /,
274
+ path: str,
275
+ mode: typing.Union[_typeshed.OpenTextMode, _typeshed.OpenBinaryMode],
276
+ client: modal.client.Client,
277
+ task_id: str,
278
+ ) -> FileIO:
279
+ """Create a new FileIO handle."""
280
+ ...
286
281
 
287
- @classmethod
288
- def create(
289
- cls,
290
- path: str,
291
- mode: typing.Union[_typeshed.OpenTextMode, _typeshed.OpenBinaryMode],
292
- client: modal.client.Client,
293
- task_id: str,
294
- ) -> FileIO:
295
- """Create a new FileIO handle."""
296
- ...
282
+ async def aio(
283
+ self,
284
+ /,
285
+ path: str,
286
+ mode: typing.Union[_typeshed.OpenTextMode, _typeshed.OpenBinaryMode],
287
+ client: modal.client.Client,
288
+ task_id: str,
289
+ ) -> FileIO:
290
+ """Create a new FileIO handle."""
291
+ ...
292
+
293
+ create: typing.ClassVar[__create_spec]
297
294
 
298
- class ___make_read_request_spec(typing_extensions.Protocol[SUPERSELF]):
295
+ class ___make_read_request_spec(typing_extensions.Protocol):
299
296
  def __call__(self, /, n: typing.Optional[int]) -> bytes: ...
300
297
  async def aio(self, /, n: typing.Optional[int]) -> bytes: ...
301
298
 
302
- _make_read_request: ___make_read_request_spec[typing_extensions.Self]
299
+ _make_read_request: ___make_read_request_spec
303
300
 
304
- class __read_spec(typing_extensions.Protocol[T_INNER, SUPERSELF]):
301
+ class __read_spec(typing_extensions.Protocol[T_INNER]):
305
302
  def __call__(self, /, n: typing.Optional[int] = None) -> T_INNER:
306
303
  """Read n bytes from the current position, or the entire remaining file if n is None."""
307
304
  ...
@@ -310,9 +307,9 @@ class FileIO(typing.Generic[T]):
310
307
  """Read n bytes from the current position, or the entire remaining file if n is None."""
311
308
  ...
312
309
 
313
- read: __read_spec[T, typing_extensions.Self]
310
+ read: __read_spec[T]
314
311
 
315
- class __readline_spec(typing_extensions.Protocol[T_INNER, SUPERSELF]):
312
+ class __readline_spec(typing_extensions.Protocol[T_INNER]):
316
313
  def __call__(self, /) -> T_INNER:
317
314
  """Read a single line from the current position."""
318
315
  ...
@@ -321,9 +318,9 @@ class FileIO(typing.Generic[T]):
321
318
  """Read a single line from the current position."""
322
319
  ...
323
320
 
324
- readline: __readline_spec[T, typing_extensions.Self]
321
+ readline: __readline_spec[T]
325
322
 
326
- class __readlines_spec(typing_extensions.Protocol[T_INNER, SUPERSELF]):
323
+ class __readlines_spec(typing_extensions.Protocol[T_INNER]):
327
324
  def __call__(self, /) -> typing.Sequence[T_INNER]:
328
325
  """Read all lines from the current position."""
329
326
  ...
@@ -332,9 +329,9 @@ class FileIO(typing.Generic[T]):
332
329
  """Read all lines from the current position."""
333
330
  ...
334
331
 
335
- readlines: __readlines_spec[T, typing_extensions.Self]
332
+ readlines: __readlines_spec[T]
336
333
 
337
- class __write_spec(typing_extensions.Protocol[SUPERSELF]):
334
+ class __write_spec(typing_extensions.Protocol):
338
335
  def __call__(self, /, data: typing.Union[bytes, str]) -> None:
339
336
  """Write data to the current position.
340
337
 
@@ -353,9 +350,9 @@ class FileIO(typing.Generic[T]):
353
350
  """
354
351
  ...
355
352
 
356
- write: __write_spec[typing_extensions.Self]
353
+ write: __write_spec
357
354
 
358
- class __flush_spec(typing_extensions.Protocol[SUPERSELF]):
355
+ class __flush_spec(typing_extensions.Protocol):
359
356
  def __call__(self, /) -> None:
360
357
  """Flush the buffer to disk."""
361
358
  ...
@@ -364,11 +361,11 @@ class FileIO(typing.Generic[T]):
364
361
  """Flush the buffer to disk."""
365
362
  ...
366
363
 
367
- flush: __flush_spec[typing_extensions.Self]
364
+ flush: __flush_spec
368
365
 
369
366
  def _get_whence(self, whence: int): ...
370
367
 
371
- class __seek_spec(typing_extensions.Protocol[SUPERSELF]):
368
+ class __seek_spec(typing_extensions.Protocol):
372
369
  def __call__(self, /, offset: int, whence: int = 0) -> None:
373
370
  """Move to a new position in the file.
374
371
 
@@ -385,41 +382,72 @@ class FileIO(typing.Generic[T]):
385
382
  """
386
383
  ...
387
384
 
388
- seek: __seek_spec[typing_extensions.Self]
385
+ seek: __seek_spec
389
386
 
390
- @classmethod
391
- def ls(cls, path: str, client: modal.client.Client, task_id: str) -> list[str]:
392
- """List the contents of the provided directory."""
393
- ...
387
+ class __ls_spec(typing_extensions.Protocol):
388
+ def __call__(self, /, path: str, client: modal.client.Client, task_id: str) -> list[str]:
389
+ """List the contents of the provided directory."""
390
+ ...
394
391
 
395
- @classmethod
396
- def mkdir(cls, path: str, client: modal.client.Client, task_id: str, parents: bool = False) -> None:
397
- """Create a new directory."""
398
- ...
392
+ async def aio(self, /, path: str, client: modal.client.Client, task_id: str) -> list[str]:
393
+ """List the contents of the provided directory."""
394
+ ...
399
395
 
400
- @classmethod
401
- def rm(cls, path: str, client: modal.client.Client, task_id: str, recursive: bool = False) -> None:
402
- """Remove a file or directory in the Sandbox."""
403
- ...
396
+ ls: typing.ClassVar[__ls_spec]
404
397
 
405
- @classmethod
406
- def watch(
407
- cls,
408
- path: str,
409
- client: modal.client.Client,
410
- task_id: str,
411
- filter: typing.Optional[list[FileWatchEventType]] = None,
412
- recursive: bool = False,
413
- timeout: typing.Optional[int] = None,
414
- ) -> typing.Iterator[FileWatchEvent]: ...
398
+ class __mkdir_spec(typing_extensions.Protocol):
399
+ def __call__(self, /, path: str, client: modal.client.Client, task_id: str, parents: bool = False) -> None:
400
+ """Create a new directory."""
401
+ ...
402
+
403
+ async def aio(self, /, path: str, client: modal.client.Client, task_id: str, parents: bool = False) -> None:
404
+ """Create a new directory."""
405
+ ...
406
+
407
+ mkdir: typing.ClassVar[__mkdir_spec]
408
+
409
+ class __rm_spec(typing_extensions.Protocol):
410
+ def __call__(self, /, path: str, client: modal.client.Client, task_id: str, recursive: bool = False) -> None:
411
+ """Remove a file or directory in the Sandbox."""
412
+ ...
413
+
414
+ async def aio(self, /, path: str, client: modal.client.Client, task_id: str, recursive: bool = False) -> None:
415
+ """Remove a file or directory in the Sandbox."""
416
+ ...
415
417
 
416
- class ___close_spec(typing_extensions.Protocol[SUPERSELF]):
418
+ rm: typing.ClassVar[__rm_spec]
419
+
420
+ class __watch_spec(typing_extensions.Protocol):
421
+ def __call__(
422
+ self,
423
+ /,
424
+ path: str,
425
+ client: modal.client.Client,
426
+ task_id: str,
427
+ filter: typing.Optional[list[FileWatchEventType]] = None,
428
+ recursive: bool = False,
429
+ timeout: typing.Optional[int] = None,
430
+ ) -> typing.Iterator[FileWatchEvent]: ...
431
+ def aio(
432
+ self,
433
+ /,
434
+ path: str,
435
+ client: modal.client.Client,
436
+ task_id: str,
437
+ filter: typing.Optional[list[FileWatchEventType]] = None,
438
+ recursive: bool = False,
439
+ timeout: typing.Optional[int] = None,
440
+ ) -> typing.AsyncIterator[FileWatchEvent]: ...
441
+
442
+ watch: typing.ClassVar[__watch_spec]
443
+
444
+ class ___close_spec(typing_extensions.Protocol):
417
445
  def __call__(self, /) -> None: ...
418
446
  async def aio(self, /) -> None: ...
419
447
 
420
- _close: ___close_spec[typing_extensions.Self]
448
+ _close: ___close_spec
421
449
 
422
- class __close_spec(typing_extensions.Protocol[SUPERSELF]):
450
+ class __close_spec(typing_extensions.Protocol):
423
451
  def __call__(self, /) -> None:
424
452
  """Flush the buffer and close the file."""
425
453
  ...
@@ -428,7 +456,7 @@ class FileIO(typing.Generic[T]):
428
456
  """Flush the buffer and close the file."""
429
457
  ...
430
458
 
431
- close: __close_spec[typing_extensions.Self]
459
+ close: __close_spec
432
460
 
433
461
  def _check_writable(self) -> None: ...
434
462
  def _check_readable(self) -> None: ...