modal 1.1.5.dev66__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 (143) 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 +171 -138
  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 +30 -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/name_utils.py +2 -3
  31. modal/_utils/package_utils.py +0 -1
  32. modal/_utils/rand_pb_testing.py +8 -1
  33. modal/_utils/task_command_router_client.py +524 -0
  34. modal/_vendor/cloudpickle.py +144 -48
  35. modal/app.py +285 -105
  36. modal/app.pyi +216 -53
  37. modal/billing.py +5 -0
  38. modal/builder/2025.06.txt +6 -3
  39. modal/builder/PREVIEW.txt +2 -1
  40. modal/builder/base-images.json +4 -2
  41. modal/cli/_download.py +19 -3
  42. modal/cli/cluster.py +4 -2
  43. modal/cli/config.py +3 -1
  44. modal/cli/container.py +5 -4
  45. modal/cli/dict.py +5 -2
  46. modal/cli/entry_point.py +26 -2
  47. modal/cli/environment.py +2 -16
  48. modal/cli/launch.py +1 -76
  49. modal/cli/network_file_system.py +5 -20
  50. modal/cli/programs/run_jupyter.py +1 -1
  51. modal/cli/programs/vscode.py +1 -1
  52. modal/cli/queues.py +5 -4
  53. modal/cli/run.py +24 -204
  54. modal/cli/secret.py +1 -2
  55. modal/cli/shell.py +375 -0
  56. modal/cli/utils.py +1 -13
  57. modal/cli/volume.py +11 -17
  58. modal/client.py +16 -125
  59. modal/client.pyi +94 -144
  60. modal/cloud_bucket_mount.py +3 -1
  61. modal/cloud_bucket_mount.pyi +4 -0
  62. modal/cls.py +101 -64
  63. modal/cls.pyi +9 -8
  64. modal/config.py +21 -1
  65. modal/container_process.py +288 -12
  66. modal/container_process.pyi +99 -38
  67. modal/dict.py +72 -33
  68. modal/dict.pyi +88 -57
  69. modal/environments.py +16 -8
  70. modal/environments.pyi +6 -2
  71. modal/exception.py +154 -16
  72. modal/experimental/__init__.py +24 -53
  73. modal/experimental/flash.py +161 -74
  74. modal/experimental/flash.pyi +97 -49
  75. modal/file_io.py +50 -92
  76. modal/file_io.pyi +117 -89
  77. modal/functions.pyi +70 -87
  78. modal/image.py +82 -47
  79. modal/image.pyi +51 -30
  80. modal/io_streams.py +500 -149
  81. modal/io_streams.pyi +279 -189
  82. modal/mount.py +60 -46
  83. modal/mount.pyi +41 -17
  84. modal/network_file_system.py +19 -11
  85. modal/network_file_system.pyi +72 -39
  86. modal/object.pyi +114 -22
  87. modal/parallel_map.py +42 -44
  88. modal/parallel_map.pyi +9 -17
  89. modal/partial_function.pyi +4 -2
  90. modal/proxy.py +14 -6
  91. modal/proxy.pyi +10 -2
  92. modal/queue.py +45 -38
  93. modal/queue.pyi +88 -52
  94. modal/runner.py +96 -96
  95. modal/runner.pyi +44 -27
  96. modal/sandbox.py +225 -107
  97. modal/sandbox.pyi +226 -60
  98. modal/secret.py +58 -56
  99. modal/secret.pyi +28 -13
  100. modal/serving.py +7 -11
  101. modal/serving.pyi +7 -8
  102. modal/snapshot.py +29 -15
  103. modal/snapshot.pyi +18 -10
  104. modal/token_flow.py +1 -1
  105. modal/token_flow.pyi +4 -6
  106. modal/volume.py +102 -55
  107. modal/volume.pyi +125 -66
  108. {modal-1.1.5.dev66.dist-info → modal-1.3.1.dev8.dist-info}/METADATA +10 -9
  109. modal-1.3.1.dev8.dist-info/RECORD +189 -0
  110. modal_proto/api.proto +141 -70
  111. modal_proto/api_grpc.py +42 -26
  112. modal_proto/api_pb2.py +1123 -1103
  113. modal_proto/api_pb2.pyi +331 -83
  114. modal_proto/api_pb2_grpc.py +80 -48
  115. modal_proto/api_pb2_grpc.pyi +26 -18
  116. modal_proto/modal_api_grpc.py +175 -174
  117. modal_proto/task_command_router.proto +164 -0
  118. modal_proto/task_command_router_grpc.py +138 -0
  119. modal_proto/task_command_router_pb2.py +180 -0
  120. modal_proto/{sandbox_router_pb2.pyi → task_command_router_pb2.pyi} +148 -57
  121. modal_proto/task_command_router_pb2_grpc.py +272 -0
  122. modal_proto/task_command_router_pb2_grpc.pyi +100 -0
  123. modal_version/__init__.py +1 -1
  124. modal_version/__main__.py +1 -1
  125. modal/cli/programs/launch_instance_ssh.py +0 -94
  126. modal/cli/programs/run_marimo.py +0 -95
  127. modal-1.1.5.dev66.dist-info/RECORD +0 -191
  128. modal_proto/modal_options_grpc.py +0 -3
  129. modal_proto/options.proto +0 -19
  130. modal_proto/options_grpc.py +0 -3
  131. modal_proto/options_pb2.py +0 -35
  132. modal_proto/options_pb2.pyi +0 -20
  133. modal_proto/options_pb2_grpc.py +0 -4
  134. modal_proto/options_pb2_grpc.pyi +0 -7
  135. modal_proto/sandbox_router.proto +0 -125
  136. modal_proto/sandbox_router_grpc.py +0 -89
  137. modal_proto/sandbox_router_pb2.py +0 -128
  138. modal_proto/sandbox_router_pb2_grpc.py +0 -169
  139. modal_proto/sandbox_router_pb2_grpc.pyi +0 -63
  140. {modal-1.1.5.dev66.dist-info → modal-1.3.1.dev8.dist-info}/WHEEL +0 -0
  141. {modal-1.1.5.dev66.dist-info → modal-1.3.1.dev8.dist-info}/entry_points.txt +0 -0
  142. {modal-1.1.5.dev66.dist-info → modal-1.3.1.dev8.dist-info}/licenses/LICENSE +0 -0
  143. {modal-1.1.5.dev66.dist-info → modal-1.3.1.dev8.dist-info}/top_level.txt +0 -0
modal/sandbox.pyi CHANGED
@@ -3,6 +3,7 @@ import collections.abc
3
3
  import google.protobuf.message
4
4
  import modal._object
5
5
  import modal._tunnel
6
+ import modal._utils.task_command_router_client
6
7
  import modal.app
7
8
  import modal.client
8
9
  import modal.cloud_bucket_mount
@@ -15,18 +16,17 @@ import modal.mount
15
16
  import modal.network_file_system
16
17
  import modal.object
17
18
  import modal.proxy
18
- import modal.scheduler_placement
19
19
  import modal.secret
20
20
  import modal.snapshot
21
21
  import modal.stream_type
22
22
  import modal.volume
23
23
  import modal_proto.api_pb2
24
24
  import os
25
+ import pathlib
25
26
  import typing
26
27
  import typing_extensions
27
28
 
28
29
  def _validate_exec_args(args: collections.abc.Sequence[str]) -> None: ...
29
- def _warn_if_invalid_name(name: str) -> None: ...
30
30
 
31
31
  class DefaultSandboxNameOverride(str):
32
32
  """A singleton class that represents the default sandbox name override.
@@ -83,6 +83,7 @@ class _Sandbox(modal._object._Object):
83
83
  _task_id: typing.Optional[str]
84
84
  _tunnels: typing.Optional[dict[int, modal._tunnel.Tunnel]]
85
85
  _enable_snapshot: bool
86
+ _command_router_client: typing.Optional[modal._utils.task_command_router_client.TaskCommandRouterClient]
86
87
 
87
88
  @staticmethod
88
89
  def _default_pty_info() -> modal_proto.api_pb2.PTYInfo: ...
@@ -115,7 +116,6 @@ class _Sandbox(modal._object._Object):
115
116
  unencrypted_ports: collections.abc.Sequence[int] = [],
116
117
  proxy: typing.Optional[modal.proxy._Proxy] = None,
117
118
  experimental_options: typing.Optional[dict[str, bool]] = None,
118
- _experimental_scheduler_placement: typing.Optional[modal.scheduler_placement.SchedulerPlacement] = None,
119
119
  enable_snapshot: bool = False,
120
120
  verbose: bool = False,
121
121
  ) -> _Sandbox:
@@ -153,7 +153,6 @@ class _Sandbox(modal._object._Object):
153
153
  verbose: bool = False,
154
154
  experimental_options: typing.Optional[dict[str, bool]] = None,
155
155
  _experimental_enable_snapshot: bool = False,
156
- _experimental_scheduler_placement: typing.Optional[modal.scheduler_placement.SchedulerPlacement] = None,
157
156
  client: typing.Optional[modal.client._Client] = None,
158
157
  environment_name: typing.Optional[str] = None,
159
158
  pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
@@ -204,7 +203,6 @@ class _Sandbox(modal._object._Object):
204
203
  proxy: typing.Optional[modal.proxy._Proxy] = None,
205
204
  experimental_options: typing.Optional[dict[str, bool]] = None,
206
205
  _experimental_enable_snapshot: bool = False,
207
- _experimental_scheduler_placement: typing.Optional[modal.scheduler_placement.SchedulerPlacement] = None,
208
206
  client: typing.Optional[modal.client._Client] = None,
209
207
  verbose: bool = False,
210
208
  pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
@@ -257,6 +255,18 @@ class _Sandbox(modal._object._Object):
257
255
  """
258
256
  ...
259
257
 
258
+ async def _experimental_mount_image(
259
+ self, path: typing.Union[pathlib.PurePosixPath, str], image: typing.Optional[modal.image._Image]
260
+ ):
261
+ """Mount an Image at a path in the Sandbox filesystem."""
262
+ ...
263
+
264
+ async def _experimental_snapshot_directory(
265
+ self, path: typing.Union[pathlib.PurePosixPath, str]
266
+ ) -> modal.image._Image:
267
+ """Snapshot local changes to a previously mounted Image, creating a new Image."""
268
+ ...
269
+
260
270
  async def wait(self, raise_on_termination: bool = True):
261
271
  """Wait for the Sandbox to finish running."""
262
272
  ...
@@ -276,10 +286,10 @@ class _Sandbox(modal._object._Object):
276
286
  async def create_connect_token(
277
287
  self, user_metadata: typing.Union[str, dict[str, typing.Any], None] = None
278
288
  ) -> SandboxConnectCredentials:
279
- """Create a token for making HTTP connections to the sandbox.
289
+ """[Alpha] Create a token for making HTTP connections to the Sandbox.
280
290
 
281
291
  Also accepts an optional user_metadata string or dict to associate with the token. This metadata
282
- will be added to the headers by the proxy when forwarding requests to the sandbox.
292
+ will be added to the headers by the proxy when forwarding requests to the Sandbox.
283
293
  """
284
294
  ...
285
295
 
@@ -305,6 +315,9 @@ class _Sandbox(modal._object._Object):
305
315
  ...
306
316
 
307
317
  async def _get_task_id(self) -> str: ...
318
+ async def _get_command_router_client(
319
+ self, task_id: str
320
+ ) -> typing.Optional[modal._utils.task_command_router_client.TaskCommandRouterClient]: ...
308
321
  @typing.overload
309
322
  async def exec(
310
323
  self,
@@ -356,6 +369,41 @@ class _Sandbox(modal._object._Object):
356
369
  """
357
370
  ...
358
371
 
372
+ async def _exec_through_server(
373
+ self,
374
+ *args: str,
375
+ task_id: str,
376
+ pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
377
+ stdout: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
378
+ stderr: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
379
+ timeout: typing.Optional[int] = None,
380
+ workdir: typing.Optional[str] = None,
381
+ secret_ids: typing.Optional[collections.abc.Collection[str]] = None,
382
+ text: bool = True,
383
+ bufsize: typing.Literal[-1, 1] = -1,
384
+ runtime_debug: bool = False,
385
+ ) -> typing.Union[modal.container_process._ContainerProcess[bytes], modal.container_process._ContainerProcess[str]]:
386
+ """Execute a command through the Modal server."""
387
+ ...
388
+
389
+ async def _exec_through_command_router(
390
+ self,
391
+ *args: str,
392
+ task_id: str,
393
+ command_router_client: modal._utils.task_command_router_client.TaskCommandRouterClient,
394
+ pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
395
+ stdout: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
396
+ stderr: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
397
+ timeout: typing.Optional[int] = None,
398
+ workdir: typing.Optional[str] = None,
399
+ secret_ids: typing.Optional[collections.abc.Collection[str]] = None,
400
+ text: bool = True,
401
+ bufsize: typing.Literal[-1, 1] = -1,
402
+ runtime_debug: bool = False,
403
+ ) -> typing.Union[modal.container_process._ContainerProcess[bytes], modal.container_process._ContainerProcess[str]]:
404
+ """Execute a command through a task command router running on the Modal worker."""
405
+ ...
406
+
359
407
  async def _experimental_snapshot(self) -> modal.snapshot._SandboxSnapshot: ...
360
408
  @staticmethod
361
409
  async def _experimental_from_snapshot(
@@ -428,8 +476,6 @@ class _Sandbox(modal._object._Object):
428
476
  """
429
477
  ...
430
478
 
431
- SUPERSELF = typing.TypeVar("SUPERSELF", covariant=True)
432
-
433
479
  class Sandbox(modal.object.Object):
434
480
  """A `Sandbox` object lets you interact with a running sandbox. This API is similar to Python's
435
481
  [asyncio.subprocess.Process](https://docs.python.org/3/library/asyncio-subprocess.html#asyncio.subprocess.Process).
@@ -444,6 +490,7 @@ class Sandbox(modal.object.Object):
444
490
  _task_id: typing.Optional[str]
445
491
  _tunnels: typing.Optional[dict[int, modal._tunnel.Tunnel]]
446
492
  _enable_snapshot: bool
493
+ _command_router_client: typing.Optional[modal._utils.task_command_router_client.TaskCommandRouterClient]
447
494
 
448
495
  def __init__(self, *args, **kwargs):
449
496
  """mdmd:hidden"""
@@ -479,7 +526,6 @@ class Sandbox(modal.object.Object):
479
526
  unencrypted_ports: collections.abc.Sequence[int] = [],
480
527
  proxy: typing.Optional[modal.proxy.Proxy] = None,
481
528
  experimental_options: typing.Optional[dict[str, bool]] = None,
482
- _experimental_scheduler_placement: typing.Optional[modal.scheduler_placement.SchedulerPlacement] = None,
483
529
  enable_snapshot: bool = False,
484
530
  verbose: bool = False,
485
531
  ) -> Sandbox:
@@ -521,7 +567,6 @@ class Sandbox(modal.object.Object):
521
567
  verbose: bool = False,
522
568
  experimental_options: typing.Optional[dict[str, bool]] = None,
523
569
  _experimental_enable_snapshot: bool = False,
524
- _experimental_scheduler_placement: typing.Optional[modal.scheduler_placement.SchedulerPlacement] = None,
525
570
  client: typing.Optional[modal.client.Client] = None,
526
571
  environment_name: typing.Optional[str] = None,
527
572
  pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
@@ -575,7 +620,6 @@ class Sandbox(modal.object.Object):
575
620
  verbose: bool = False,
576
621
  experimental_options: typing.Optional[dict[str, bool]] = None,
577
622
  _experimental_enable_snapshot: bool = False,
578
- _experimental_scheduler_placement: typing.Optional[modal.scheduler_placement.SchedulerPlacement] = None,
579
623
  client: typing.Optional[modal.client.Client] = None,
580
624
  environment_name: typing.Optional[str] = None,
581
625
  pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
@@ -595,7 +639,7 @@ class Sandbox(modal.object.Object):
595
639
  """
596
640
  ...
597
641
 
598
- create: __create_spec
642
+ create: typing.ClassVar[__create_spec]
599
643
 
600
644
  class ___create_spec(typing_extensions.Protocol):
601
645
  def __call__(
@@ -632,7 +676,6 @@ class Sandbox(modal.object.Object):
632
676
  proxy: typing.Optional[modal.proxy.Proxy] = None,
633
677
  experimental_options: typing.Optional[dict[str, bool]] = None,
634
678
  _experimental_enable_snapshot: bool = False,
635
- _experimental_scheduler_placement: typing.Optional[modal.scheduler_placement.SchedulerPlacement] = None,
636
679
  client: typing.Optional[modal.client.Client] = None,
637
680
  verbose: bool = False,
638
681
  pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
@@ -679,7 +722,6 @@ class Sandbox(modal.object.Object):
679
722
  proxy: typing.Optional[modal.proxy.Proxy] = None,
680
723
  experimental_options: typing.Optional[dict[str, bool]] = None,
681
724
  _experimental_enable_snapshot: bool = False,
682
- _experimental_scheduler_placement: typing.Optional[modal.scheduler_placement.SchedulerPlacement] = None,
683
725
  client: typing.Optional[modal.client.Client] = None,
684
726
  verbose: bool = False,
685
727
  pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
@@ -692,7 +734,7 @@ class Sandbox(modal.object.Object):
692
734
  """
693
735
  ...
694
736
 
695
- _create: ___create_spec
737
+ _create: typing.ClassVar[___create_spec]
696
738
 
697
739
  def _hydrate_metadata(self, handle_metadata: typing.Optional[google.protobuf.message.Message]): ...
698
740
 
@@ -729,7 +771,7 @@ class Sandbox(modal.object.Object):
729
771
  """
730
772
  ...
731
773
 
732
- from_name: __from_name_spec
774
+ from_name: typing.ClassVar[__from_name_spec]
733
775
 
734
776
  class __from_id_spec(typing_extensions.Protocol):
735
777
  def __call__(self, /, sandbox_id: str, client: typing.Optional[modal.client.Client] = None) -> Sandbox:
@@ -746,9 +788,9 @@ class Sandbox(modal.object.Object):
746
788
  """
747
789
  ...
748
790
 
749
- from_id: __from_id_spec
791
+ from_id: typing.ClassVar[__from_id_spec]
750
792
 
751
- class __get_tags_spec(typing_extensions.Protocol[SUPERSELF]):
793
+ class __get_tags_spec(typing_extensions.Protocol):
752
794
  def __call__(self, /) -> dict[str, str]:
753
795
  """Fetches any tags (key-value pairs) currently attached to this Sandbox from the server."""
754
796
  ...
@@ -757,9 +799,9 @@ class Sandbox(modal.object.Object):
757
799
  """Fetches any tags (key-value pairs) currently attached to this Sandbox from the server."""
758
800
  ...
759
801
 
760
- get_tags: __get_tags_spec[typing_extensions.Self]
802
+ get_tags: __get_tags_spec
761
803
 
762
- class __set_tags_spec(typing_extensions.Protocol[SUPERSELF]):
804
+ class __set_tags_spec(typing_extensions.Protocol):
763
805
  def __call__(self, /, tags: dict[str, str], *, client: typing.Optional[modal.client.Client] = None) -> None:
764
806
  """Set tags (key-value pairs) on the Sandbox. Tags can be used to filter results in `Sandbox.list`."""
765
807
  ...
@@ -768,9 +810,9 @@ class Sandbox(modal.object.Object):
768
810
  """Set tags (key-value pairs) on the Sandbox. Tags can be used to filter results in `Sandbox.list`."""
769
811
  ...
770
812
 
771
- set_tags: __set_tags_spec[typing_extensions.Self]
813
+ set_tags: __set_tags_spec
772
814
 
773
- class __snapshot_filesystem_spec(typing_extensions.Protocol[SUPERSELF]):
815
+ class __snapshot_filesystem_spec(typing_extensions.Protocol):
774
816
  def __call__(self, /, timeout: int = 55) -> modal.image.Image:
775
817
  """Snapshot the filesystem of the Sandbox.
776
818
 
@@ -787,9 +829,35 @@ class Sandbox(modal.object.Object):
787
829
  """
788
830
  ...
789
831
 
790
- snapshot_filesystem: __snapshot_filesystem_spec[typing_extensions.Self]
832
+ snapshot_filesystem: __snapshot_filesystem_spec
833
+
834
+ class ___experimental_mount_image_spec(typing_extensions.Protocol):
835
+ def __call__(
836
+ self, /, path: typing.Union[pathlib.PurePosixPath, str], image: typing.Optional[modal.image.Image]
837
+ ):
838
+ """Mount an Image at a path in the Sandbox filesystem."""
839
+ ...
840
+
841
+ async def aio(
842
+ self, /, path: typing.Union[pathlib.PurePosixPath, str], image: typing.Optional[modal.image.Image]
843
+ ):
844
+ """Mount an Image at a path in the Sandbox filesystem."""
845
+ ...
846
+
847
+ _experimental_mount_image: ___experimental_mount_image_spec
848
+
849
+ class ___experimental_snapshot_directory_spec(typing_extensions.Protocol):
850
+ def __call__(self, /, path: typing.Union[pathlib.PurePosixPath, str]) -> modal.image.Image:
851
+ """Snapshot local changes to a previously mounted Image, creating a new Image."""
852
+ ...
853
+
854
+ async def aio(self, /, path: typing.Union[pathlib.PurePosixPath, str]) -> modal.image.Image:
855
+ """Snapshot local changes to a previously mounted Image, creating a new Image."""
856
+ ...
857
+
858
+ _experimental_snapshot_directory: ___experimental_snapshot_directory_spec
791
859
 
792
- class __wait_spec(typing_extensions.Protocol[SUPERSELF]):
860
+ class __wait_spec(typing_extensions.Protocol):
793
861
  def __call__(self, /, raise_on_termination: bool = True):
794
862
  """Wait for the Sandbox to finish running."""
795
863
  ...
@@ -798,9 +866,9 @@ class Sandbox(modal.object.Object):
798
866
  """Wait for the Sandbox to finish running."""
799
867
  ...
800
868
 
801
- wait: __wait_spec[typing_extensions.Self]
869
+ wait: __wait_spec
802
870
 
803
- class __tunnels_spec(typing_extensions.Protocol[SUPERSELF]):
871
+ class __tunnels_spec(typing_extensions.Protocol):
804
872
  def __call__(self, /, timeout: int = 50) -> dict[int, modal._tunnel.Tunnel]:
805
873
  """Get Tunnel metadata for the sandbox.
806
874
 
@@ -825,32 +893,32 @@ class Sandbox(modal.object.Object):
825
893
  """
826
894
  ...
827
895
 
828
- tunnels: __tunnels_spec[typing_extensions.Self]
896
+ tunnels: __tunnels_spec
829
897
 
830
- class __create_connect_token_spec(typing_extensions.Protocol[SUPERSELF]):
898
+ class __create_connect_token_spec(typing_extensions.Protocol):
831
899
  def __call__(
832
900
  self, /, user_metadata: typing.Union[str, dict[str, typing.Any], None] = None
833
901
  ) -> SandboxConnectCredentials:
834
- """Create a token for making HTTP connections to the sandbox.
902
+ """[Alpha] Create a token for making HTTP connections to the Sandbox.
835
903
 
836
904
  Also accepts an optional user_metadata string or dict to associate with the token. This metadata
837
- will be added to the headers by the proxy when forwarding requests to the sandbox.
905
+ will be added to the headers by the proxy when forwarding requests to the Sandbox.
838
906
  """
839
907
  ...
840
908
 
841
909
  async def aio(
842
910
  self, /, user_metadata: typing.Union[str, dict[str, typing.Any], None] = None
843
911
  ) -> SandboxConnectCredentials:
844
- """Create a token for making HTTP connections to the sandbox.
912
+ """[Alpha] Create a token for making HTTP connections to the Sandbox.
845
913
 
846
914
  Also accepts an optional user_metadata string or dict to associate with the token. This metadata
847
- will be added to the headers by the proxy when forwarding requests to the sandbox.
915
+ will be added to the headers by the proxy when forwarding requests to the Sandbox.
848
916
  """
849
917
  ...
850
918
 
851
- create_connect_token: __create_connect_token_spec[typing_extensions.Self]
919
+ create_connect_token: __create_connect_token_spec
852
920
 
853
- class __reload_volumes_spec(typing_extensions.Protocol[SUPERSELF]):
921
+ class __reload_volumes_spec(typing_extensions.Protocol):
854
922
  def __call__(self, /) -> None:
855
923
  """Reload all Volumes mounted in the Sandbox.
856
924
 
@@ -865,9 +933,9 @@ class Sandbox(modal.object.Object):
865
933
  """
866
934
  ...
867
935
 
868
- reload_volumes: __reload_volumes_spec[typing_extensions.Self]
936
+ reload_volumes: __reload_volumes_spec
869
937
 
870
- class __terminate_spec(typing_extensions.Protocol[SUPERSELF]):
938
+ class __terminate_spec(typing_extensions.Protocol):
871
939
  def __call__(self, /) -> None:
872
940
  """Terminate Sandbox execution.
873
941
 
@@ -882,9 +950,9 @@ class Sandbox(modal.object.Object):
882
950
  """
883
951
  ...
884
952
 
885
- terminate: __terminate_spec[typing_extensions.Self]
953
+ terminate: __terminate_spec
886
954
 
887
- class __poll_spec(typing_extensions.Protocol[SUPERSELF]):
955
+ class __poll_spec(typing_extensions.Protocol):
888
956
  def __call__(self, /) -> typing.Optional[int]:
889
957
  """Check if the Sandbox has finished running.
890
958
 
@@ -899,15 +967,25 @@ class Sandbox(modal.object.Object):
899
967
  """
900
968
  ...
901
969
 
902
- poll: __poll_spec[typing_extensions.Self]
970
+ poll: __poll_spec
903
971
 
904
- class ___get_task_id_spec(typing_extensions.Protocol[SUPERSELF]):
972
+ class ___get_task_id_spec(typing_extensions.Protocol):
905
973
  def __call__(self, /) -> str: ...
906
974
  async def aio(self, /) -> str: ...
907
975
 
908
- _get_task_id: ___get_task_id_spec[typing_extensions.Self]
976
+ _get_task_id: ___get_task_id_spec
977
+
978
+ class ___get_command_router_client_spec(typing_extensions.Protocol):
979
+ def __call__(
980
+ self, /, task_id: str
981
+ ) -> typing.Optional[modal._utils.task_command_router_client.TaskCommandRouterClient]: ...
982
+ async def aio(
983
+ self, /, task_id: str
984
+ ) -> typing.Optional[modal._utils.task_command_router_client.TaskCommandRouterClient]: ...
909
985
 
910
- class __exec_spec(typing_extensions.Protocol[SUPERSELF]):
986
+ _get_command_router_client: ___get_command_router_client_spec
987
+
988
+ class __exec_spec(typing_extensions.Protocol):
911
989
  @typing.overload
912
990
  def __call__(
913
991
  self,
@@ -977,9 +1055,9 @@ class Sandbox(modal.object.Object):
977
1055
  _pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
978
1056
  ) -> modal.container_process.ContainerProcess[bytes]: ...
979
1057
 
980
- exec: __exec_spec[typing_extensions.Self]
1058
+ exec: __exec_spec
981
1059
 
982
- class ___exec_spec(typing_extensions.Protocol[SUPERSELF]):
1060
+ class ___exec_spec(typing_extensions.Protocol):
983
1061
  def __call__(
984
1062
  self,
985
1063
  /,
@@ -1024,13 +1102,101 @@ class Sandbox(modal.object.Object):
1024
1102
  """
1025
1103
  ...
1026
1104
 
1027
- _exec: ___exec_spec[typing_extensions.Self]
1105
+ _exec: ___exec_spec
1106
+
1107
+ class ___exec_through_server_spec(typing_extensions.Protocol):
1108
+ def __call__(
1109
+ self,
1110
+ /,
1111
+ *args: str,
1112
+ task_id: str,
1113
+ pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
1114
+ stdout: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
1115
+ stderr: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
1116
+ timeout: typing.Optional[int] = None,
1117
+ workdir: typing.Optional[str] = None,
1118
+ secret_ids: typing.Optional[collections.abc.Collection[str]] = None,
1119
+ text: bool = True,
1120
+ bufsize: typing.Literal[-1, 1] = -1,
1121
+ runtime_debug: bool = False,
1122
+ ) -> typing.Union[
1123
+ modal.container_process.ContainerProcess[bytes], modal.container_process.ContainerProcess[str]
1124
+ ]:
1125
+ """Execute a command through the Modal server."""
1126
+ ...
1127
+
1128
+ async def aio(
1129
+ self,
1130
+ /,
1131
+ *args: str,
1132
+ task_id: str,
1133
+ pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
1134
+ stdout: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
1135
+ stderr: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
1136
+ timeout: typing.Optional[int] = None,
1137
+ workdir: typing.Optional[str] = None,
1138
+ secret_ids: typing.Optional[collections.abc.Collection[str]] = None,
1139
+ text: bool = True,
1140
+ bufsize: typing.Literal[-1, 1] = -1,
1141
+ runtime_debug: bool = False,
1142
+ ) -> typing.Union[
1143
+ modal.container_process.ContainerProcess[bytes], modal.container_process.ContainerProcess[str]
1144
+ ]:
1145
+ """Execute a command through the Modal server."""
1146
+ ...
1147
+
1148
+ _exec_through_server: ___exec_through_server_spec
1149
+
1150
+ class ___exec_through_command_router_spec(typing_extensions.Protocol):
1151
+ def __call__(
1152
+ self,
1153
+ /,
1154
+ *args: str,
1155
+ task_id: str,
1156
+ command_router_client: modal._utils.task_command_router_client.TaskCommandRouterClient,
1157
+ pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
1158
+ stdout: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
1159
+ stderr: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
1160
+ timeout: typing.Optional[int] = None,
1161
+ workdir: typing.Optional[str] = None,
1162
+ secret_ids: typing.Optional[collections.abc.Collection[str]] = None,
1163
+ text: bool = True,
1164
+ bufsize: typing.Literal[-1, 1] = -1,
1165
+ runtime_debug: bool = False,
1166
+ ) -> typing.Union[
1167
+ modal.container_process.ContainerProcess[bytes], modal.container_process.ContainerProcess[str]
1168
+ ]:
1169
+ """Execute a command through a task command router running on the Modal worker."""
1170
+ ...
1171
+
1172
+ async def aio(
1173
+ self,
1174
+ /,
1175
+ *args: str,
1176
+ task_id: str,
1177
+ command_router_client: modal._utils.task_command_router_client.TaskCommandRouterClient,
1178
+ pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
1179
+ stdout: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
1180
+ stderr: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
1181
+ timeout: typing.Optional[int] = None,
1182
+ workdir: typing.Optional[str] = None,
1183
+ secret_ids: typing.Optional[collections.abc.Collection[str]] = None,
1184
+ text: bool = True,
1185
+ bufsize: typing.Literal[-1, 1] = -1,
1186
+ runtime_debug: bool = False,
1187
+ ) -> typing.Union[
1188
+ modal.container_process.ContainerProcess[bytes], modal.container_process.ContainerProcess[str]
1189
+ ]:
1190
+ """Execute a command through a task command router running on the Modal worker."""
1191
+ ...
1192
+
1193
+ _exec_through_command_router: ___exec_through_command_router_spec
1028
1194
 
1029
- class ___experimental_snapshot_spec(typing_extensions.Protocol[SUPERSELF]):
1195
+ class ___experimental_snapshot_spec(typing_extensions.Protocol):
1030
1196
  def __call__(self, /) -> modal.snapshot.SandboxSnapshot: ...
1031
1197
  async def aio(self, /) -> modal.snapshot.SandboxSnapshot: ...
1032
1198
 
1033
- _experimental_snapshot: ___experimental_snapshot_spec[typing_extensions.Self]
1199
+ _experimental_snapshot: ___experimental_snapshot_spec
1034
1200
 
1035
1201
  class ___experimental_from_snapshot_spec(typing_extensions.Protocol):
1036
1202
  def __call__(
@@ -1050,9 +1216,9 @@ class Sandbox(modal.object.Object):
1050
1216
  name: typing.Optional[str] = _DEFAULT_SANDBOX_NAME_OVERRIDE,
1051
1217
  ): ...
1052
1218
 
1053
- _experimental_from_snapshot: ___experimental_from_snapshot_spec
1219
+ _experimental_from_snapshot: typing.ClassVar[___experimental_from_snapshot_spec]
1054
1220
 
1055
- class __open_spec(typing_extensions.Protocol[SUPERSELF]):
1221
+ class __open_spec(typing_extensions.Protocol):
1056
1222
  @typing.overload
1057
1223
  def __call__(self, /, path: str, mode: _typeshed.OpenTextMode) -> modal.file_io.FileIO[str]: ...
1058
1224
  @typing.overload
@@ -1062,9 +1228,9 @@ class Sandbox(modal.object.Object):
1062
1228
  @typing.overload
1063
1229
  async def aio(self, /, path: str, mode: _typeshed.OpenBinaryMode) -> modal.file_io.FileIO[bytes]: ...
1064
1230
 
1065
- open: __open_spec[typing_extensions.Self]
1231
+ open: __open_spec
1066
1232
 
1067
- class __ls_spec(typing_extensions.Protocol[SUPERSELF]):
1233
+ class __ls_spec(typing_extensions.Protocol):
1068
1234
  def __call__(self, /, path: str) -> list[str]:
1069
1235
  """[Alpha] List the contents of a directory in the Sandbox."""
1070
1236
  ...
@@ -1073,9 +1239,9 @@ class Sandbox(modal.object.Object):
1073
1239
  """[Alpha] List the contents of a directory in the Sandbox."""
1074
1240
  ...
1075
1241
 
1076
- ls: __ls_spec[typing_extensions.Self]
1242
+ ls: __ls_spec
1077
1243
 
1078
- class __mkdir_spec(typing_extensions.Protocol[SUPERSELF]):
1244
+ class __mkdir_spec(typing_extensions.Protocol):
1079
1245
  def __call__(self, /, path: str, parents: bool = False) -> None:
1080
1246
  """[Alpha] Create a new directory in the Sandbox."""
1081
1247
  ...
@@ -1084,9 +1250,9 @@ class Sandbox(modal.object.Object):
1084
1250
  """[Alpha] Create a new directory in the Sandbox."""
1085
1251
  ...
1086
1252
 
1087
- mkdir: __mkdir_spec[typing_extensions.Self]
1253
+ mkdir: __mkdir_spec
1088
1254
 
1089
- class __rm_spec(typing_extensions.Protocol[SUPERSELF]):
1255
+ class __rm_spec(typing_extensions.Protocol):
1090
1256
  def __call__(self, /, path: str, recursive: bool = False) -> None:
1091
1257
  """[Alpha] Remove a file or directory in the Sandbox."""
1092
1258
  ...
@@ -1095,9 +1261,9 @@ class Sandbox(modal.object.Object):
1095
1261
  """[Alpha] Remove a file or directory in the Sandbox."""
1096
1262
  ...
1097
1263
 
1098
- rm: __rm_spec[typing_extensions.Self]
1264
+ rm: __rm_spec
1099
1265
 
1100
- class __watch_spec(typing_extensions.Protocol[SUPERSELF]):
1266
+ class __watch_spec(typing_extensions.Protocol):
1101
1267
  def __call__(
1102
1268
  self,
1103
1269
  /,
@@ -1120,7 +1286,7 @@ class Sandbox(modal.object.Object):
1120
1286
  """[Alpha] Watch a file or directory in the Sandbox for changes."""
1121
1287
  ...
1122
1288
 
1123
- watch: __watch_spec[typing_extensions.Self]
1289
+ watch: __watch_spec
1124
1290
 
1125
1291
  @property
1126
1292
  def stdout(self) -> modal.io_streams.StreamReader[str]:
@@ -1175,6 +1341,6 @@ class Sandbox(modal.object.Object):
1175
1341
  """
1176
1342
  ...
1177
1343
 
1178
- list: __list_spec
1344
+ list: typing.ClassVar[__list_spec]
1179
1345
 
1180
1346
  _default_image: modal.image._Image