modal 1.0.3.dev10__py3-none-any.whl → 1.2.3.dev7__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of modal might be problematic. Click here for more details.

Files changed (160) hide show
  1. modal/__init__.py +0 -2
  2. modal/__main__.py +3 -4
  3. modal/_billing.py +80 -0
  4. modal/_clustered_functions.py +7 -3
  5. modal/_clustered_functions.pyi +15 -3
  6. modal/_container_entrypoint.py +51 -69
  7. modal/_functions.py +508 -240
  8. modal/_grpc_client.py +171 -0
  9. modal/_load_context.py +105 -0
  10. modal/_object.py +81 -21
  11. modal/_output.py +58 -45
  12. modal/_partial_function.py +48 -73
  13. modal/_pty.py +7 -3
  14. modal/_resolver.py +26 -46
  15. modal/_runtime/asgi.py +4 -3
  16. modal/_runtime/container_io_manager.py +358 -220
  17. modal/_runtime/container_io_manager.pyi +296 -101
  18. modal/_runtime/execution_context.py +18 -2
  19. modal/_runtime/execution_context.pyi +64 -7
  20. modal/_runtime/gpu_memory_snapshot.py +262 -57
  21. modal/_runtime/user_code_imports.py +28 -58
  22. modal/_serialization.py +90 -6
  23. modal/_traceback.py +42 -1
  24. modal/_tunnel.pyi +380 -12
  25. modal/_utils/async_utils.py +84 -29
  26. modal/_utils/auth_token_manager.py +111 -0
  27. modal/_utils/blob_utils.py +181 -58
  28. modal/_utils/deprecation.py +19 -0
  29. modal/_utils/function_utils.py +91 -47
  30. modal/_utils/grpc_utils.py +89 -66
  31. modal/_utils/mount_utils.py +26 -1
  32. modal/_utils/name_utils.py +17 -3
  33. modal/_utils/task_command_router_client.py +536 -0
  34. modal/_utils/time_utils.py +34 -6
  35. modal/app.py +256 -88
  36. modal/app.pyi +909 -92
  37. modal/billing.py +5 -0
  38. modal/builder/2025.06.txt +18 -0
  39. modal/builder/PREVIEW.txt +18 -0
  40. modal/builder/base-images.json +58 -0
  41. modal/cli/_download.py +19 -3
  42. modal/cli/_traceback.py +3 -2
  43. modal/cli/app.py +4 -4
  44. modal/cli/cluster.py +15 -7
  45. modal/cli/config.py +5 -3
  46. modal/cli/container.py +7 -6
  47. modal/cli/dict.py +22 -16
  48. modal/cli/entry_point.py +12 -5
  49. modal/cli/environment.py +5 -4
  50. modal/cli/import_refs.py +3 -3
  51. modal/cli/launch.py +102 -5
  52. modal/cli/network_file_system.py +11 -12
  53. modal/cli/profile.py +3 -2
  54. modal/cli/programs/launch_instance_ssh.py +94 -0
  55. modal/cli/programs/run_jupyter.py +1 -1
  56. modal/cli/programs/run_marimo.py +95 -0
  57. modal/cli/programs/vscode.py +1 -1
  58. modal/cli/queues.py +57 -26
  59. modal/cli/run.py +91 -23
  60. modal/cli/secret.py +48 -22
  61. modal/cli/token.py +7 -8
  62. modal/cli/utils.py +4 -7
  63. modal/cli/volume.py +31 -25
  64. modal/client.py +15 -85
  65. modal/client.pyi +183 -62
  66. modal/cloud_bucket_mount.py +5 -3
  67. modal/cloud_bucket_mount.pyi +197 -5
  68. modal/cls.py +200 -126
  69. modal/cls.pyi +446 -68
  70. modal/config.py +29 -11
  71. modal/container_process.py +319 -19
  72. modal/container_process.pyi +190 -20
  73. modal/dict.py +290 -71
  74. modal/dict.pyi +835 -83
  75. modal/environments.py +15 -27
  76. modal/environments.pyi +46 -24
  77. modal/exception.py +14 -2
  78. modal/experimental/__init__.py +194 -40
  79. modal/experimental/flash.py +618 -0
  80. modal/experimental/flash.pyi +380 -0
  81. modal/experimental/ipython.py +11 -7
  82. modal/file_io.py +29 -36
  83. modal/file_io.pyi +251 -53
  84. modal/file_pattern_matcher.py +56 -16
  85. modal/functions.pyi +673 -92
  86. modal/gpu.py +1 -1
  87. modal/image.py +528 -176
  88. modal/image.pyi +1572 -145
  89. modal/io_streams.py +458 -128
  90. modal/io_streams.pyi +433 -52
  91. modal/mount.py +216 -151
  92. modal/mount.pyi +225 -78
  93. modal/network_file_system.py +45 -62
  94. modal/network_file_system.pyi +277 -56
  95. modal/object.pyi +93 -17
  96. modal/parallel_map.py +942 -129
  97. modal/parallel_map.pyi +294 -15
  98. modal/partial_function.py +0 -2
  99. modal/partial_function.pyi +234 -19
  100. modal/proxy.py +17 -8
  101. modal/proxy.pyi +36 -3
  102. modal/queue.py +270 -65
  103. modal/queue.pyi +817 -57
  104. modal/runner.py +115 -101
  105. modal/runner.pyi +205 -49
  106. modal/sandbox.py +512 -136
  107. modal/sandbox.pyi +845 -111
  108. modal/schedule.py +1 -1
  109. modal/secret.py +300 -70
  110. modal/secret.pyi +589 -34
  111. modal/serving.py +7 -11
  112. modal/serving.pyi +7 -8
  113. modal/snapshot.py +11 -8
  114. modal/snapshot.pyi +25 -4
  115. modal/token_flow.py +4 -4
  116. modal/token_flow.pyi +28 -8
  117. modal/volume.py +416 -158
  118. modal/volume.pyi +1117 -121
  119. {modal-1.0.3.dev10.dist-info → modal-1.2.3.dev7.dist-info}/METADATA +10 -9
  120. modal-1.2.3.dev7.dist-info/RECORD +195 -0
  121. modal_docs/mdmd/mdmd.py +17 -4
  122. modal_proto/api.proto +534 -79
  123. modal_proto/api_grpc.py +337 -1
  124. modal_proto/api_pb2.py +1522 -968
  125. modal_proto/api_pb2.pyi +1619 -134
  126. modal_proto/api_pb2_grpc.py +699 -4
  127. modal_proto/api_pb2_grpc.pyi +226 -14
  128. modal_proto/modal_api_grpc.py +175 -154
  129. modal_proto/sandbox_router.proto +145 -0
  130. modal_proto/sandbox_router_grpc.py +105 -0
  131. modal_proto/sandbox_router_pb2.py +149 -0
  132. modal_proto/sandbox_router_pb2.pyi +333 -0
  133. modal_proto/sandbox_router_pb2_grpc.py +203 -0
  134. modal_proto/sandbox_router_pb2_grpc.pyi +75 -0
  135. modal_proto/task_command_router.proto +144 -0
  136. modal_proto/task_command_router_grpc.py +105 -0
  137. modal_proto/task_command_router_pb2.py +149 -0
  138. modal_proto/task_command_router_pb2.pyi +333 -0
  139. modal_proto/task_command_router_pb2_grpc.py +203 -0
  140. modal_proto/task_command_router_pb2_grpc.pyi +75 -0
  141. modal_version/__init__.py +1 -1
  142. modal/requirements/PREVIEW.txt +0 -16
  143. modal/requirements/base-images.json +0 -26
  144. modal-1.0.3.dev10.dist-info/RECORD +0 -179
  145. modal_proto/modal_options_grpc.py +0 -3
  146. modal_proto/options.proto +0 -19
  147. modal_proto/options_grpc.py +0 -3
  148. modal_proto/options_pb2.py +0 -35
  149. modal_proto/options_pb2.pyi +0 -20
  150. modal_proto/options_pb2_grpc.py +0 -4
  151. modal_proto/options_pb2_grpc.pyi +0 -7
  152. /modal/{requirements → builder}/2023.12.312.txt +0 -0
  153. /modal/{requirements → builder}/2023.12.txt +0 -0
  154. /modal/{requirements → builder}/2024.04.txt +0 -0
  155. /modal/{requirements → builder}/2024.10.txt +0 -0
  156. /modal/{requirements → builder}/README.md +0 -0
  157. {modal-1.0.3.dev10.dist-info → modal-1.2.3.dev7.dist-info}/WHEEL +0 -0
  158. {modal-1.0.3.dev10.dist-info → modal-1.2.3.dev7.dist-info}/entry_points.txt +0 -0
  159. {modal-1.0.3.dev10.dist-info → modal-1.2.3.dev7.dist-info}/licenses/LICENSE +0 -0
  160. {modal-1.0.3.dev10.dist-info → modal-1.2.3.dev7.dist-info}/top_level.txt +0 -0
modal/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
@@ -25,9 +26,56 @@ import os
25
26
  import typing
26
27
  import typing_extensions
27
28
 
28
- def _validate_exec_args(entrypoint_args: collections.abc.Sequence[str]) -> None: ...
29
+ def _validate_exec_args(args: collections.abc.Sequence[str]) -> None: ...
30
+
31
+ class DefaultSandboxNameOverride(str):
32
+ """A singleton class that represents the default sandbox name override.
33
+
34
+ It is used to indicate that the sandbox name should not be overridden.
35
+ """
36
+ def __repr__(self) -> str:
37
+ """Return repr(self)."""
38
+ ...
39
+
40
+ _DEFAULT_SANDBOX_NAME_OVERRIDE: DefaultSandboxNameOverride
41
+
42
+ class SandboxConnectCredentials:
43
+ """Simple data structure storing credentials for making HTTP connections to a sandbox."""
44
+
45
+ url: str
46
+ token: str
47
+
48
+ def __init__(self, url: str, token: str) -> None:
49
+ """Initialize self. See help(type(self)) for accurate signature."""
50
+ ...
51
+
52
+ def __repr__(self):
53
+ """Return repr(self)."""
54
+ ...
55
+
56
+ def __eq__(self, other):
57
+ """Return self==value."""
58
+ ...
59
+
60
+ def __setattr__(self, name, value):
61
+ """Implement setattr(self, name, value)."""
62
+ ...
63
+
64
+ def __delattr__(self, name):
65
+ """Implement delattr(self, name)."""
66
+ ...
67
+
68
+ def __hash__(self):
69
+ """Return hash(self)."""
70
+ ...
29
71
 
30
72
  class _Sandbox(modal._object._Object):
73
+ """A `Sandbox` object lets you interact with a running sandbox. This API is similar to Python's
74
+ [asyncio.subprocess.Process](https://docs.python.org/3/library/asyncio-subprocess.html#asyncio.subprocess.Process).
75
+
76
+ Refer to the [guide](https://modal.com/docs/guide/sandbox) on how to spawn and use sandboxes.
77
+ """
78
+
31
79
  _result: typing.Optional[modal_proto.api_pb2.GenericResult]
32
80
  _stdout: modal.io_streams._StreamReader[str]
33
81
  _stderr: modal.io_streams._StreamReader[str]
@@ -35,13 +83,18 @@ class _Sandbox(modal._object._Object):
35
83
  _task_id: typing.Optional[str]
36
84
  _tunnels: typing.Optional[dict[int, modal._tunnel.Tunnel]]
37
85
  _enable_snapshot: bool
86
+ _command_router_client: typing.Optional[modal._utils.task_command_router_client.TaskCommandRouterClient]
38
87
 
88
+ @staticmethod
89
+ def _default_pty_info() -> modal_proto.api_pb2.PTYInfo: ...
39
90
  @staticmethod
40
91
  def _new(
41
- entrypoint_args: collections.abc.Sequence[str],
92
+ args: collections.abc.Sequence[str],
42
93
  image: modal.image._Image,
43
- secrets: collections.abc.Sequence[modal.secret._Secret],
44
- timeout: typing.Optional[int] = None,
94
+ secrets: collections.abc.Collection[modal.secret._Secret],
95
+ name: typing.Optional[str] = None,
96
+ timeout: int = 300,
97
+ idle_timeout: typing.Optional[int] = None,
45
98
  workdir: typing.Optional[str] = None,
46
99
  gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
47
100
  cloud: typing.Optional[str] = None,
@@ -56,22 +109,31 @@ class _Sandbox(modal._object._Object):
56
109
  typing.Union[str, os.PathLike],
57
110
  typing.Union[modal.volume._Volume, modal.cloud_bucket_mount._CloudBucketMount],
58
111
  ] = {},
112
+ pty: bool = False,
59
113
  pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
60
114
  encrypted_ports: collections.abc.Sequence[int] = [],
115
+ h2_ports: collections.abc.Sequence[int] = [],
61
116
  unencrypted_ports: collections.abc.Sequence[int] = [],
62
117
  proxy: typing.Optional[modal.proxy._Proxy] = None,
118
+ experimental_options: typing.Optional[dict[str, bool]] = None,
63
119
  _experimental_scheduler_placement: typing.Optional[modal.scheduler_placement.SchedulerPlacement] = None,
64
120
  enable_snapshot: bool = False,
65
- ) -> _Sandbox: ...
121
+ verbose: bool = False,
122
+ ) -> _Sandbox:
123
+ """mdmd:hidden"""
124
+ ...
125
+
66
126
  @staticmethod
67
127
  async def create(
68
- *entrypoint_args: str,
128
+ *args: str,
69
129
  app: typing.Optional[modal.app._App] = None,
70
- environment_name: typing.Optional[str] = None,
130
+ name: typing.Optional[str] = None,
71
131
  image: typing.Optional[modal.image._Image] = None,
72
- secrets: collections.abc.Sequence[modal.secret._Secret] = (),
132
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
133
+ secrets: typing.Optional[collections.abc.Collection[modal.secret._Secret]] = None,
73
134
  network_file_systems: dict[typing.Union[str, os.PathLike], modal.network_file_system._NetworkFileSystem] = {},
74
- timeout: typing.Optional[int] = None,
135
+ timeout: int = 300,
136
+ idle_timeout: typing.Optional[int] = None,
75
137
  workdir: typing.Optional[str] = None,
76
138
  gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
77
139
  cloud: typing.Optional[str] = None,
@@ -84,24 +146,46 @@ class _Sandbox(modal._object._Object):
84
146
  typing.Union[str, os.PathLike],
85
147
  typing.Union[modal.volume._Volume, modal.cloud_bucket_mount._CloudBucketMount],
86
148
  ] = {},
87
- pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
149
+ pty: bool = False,
88
150
  encrypted_ports: collections.abc.Sequence[int] = [],
151
+ h2_ports: collections.abc.Sequence[int] = [],
89
152
  unencrypted_ports: collections.abc.Sequence[int] = [],
90
153
  proxy: typing.Optional[modal.proxy._Proxy] = None,
154
+ verbose: bool = False,
155
+ experimental_options: typing.Optional[dict[str, bool]] = None,
91
156
  _experimental_enable_snapshot: bool = False,
92
157
  _experimental_scheduler_placement: typing.Optional[modal.scheduler_placement.SchedulerPlacement] = None,
93
158
  client: typing.Optional[modal.client._Client] = None,
94
- ) -> _Sandbox: ...
159
+ environment_name: typing.Optional[str] = None,
160
+ pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
161
+ ) -> _Sandbox:
162
+ """Create a new Sandbox to run untrusted, arbitrary code.
163
+
164
+ The Sandbox's corresponding container will be created asynchronously.
165
+
166
+ **Usage**
167
+
168
+ ```python
169
+ app = modal.App.lookup('sandbox-hello-world', create_if_missing=True)
170
+ sandbox = modal.Sandbox.create("echo", "hello world", app=app)
171
+ print(sandbox.stdout.read())
172
+ sandbox.wait()
173
+ ```
174
+ """
175
+ ...
176
+
95
177
  @staticmethod
96
178
  async def _create(
97
- *entrypoint_args: str,
179
+ *args: str,
98
180
  app: typing.Optional[modal.app._App] = None,
99
- environment_name: typing.Optional[str] = None,
181
+ name: typing.Optional[str] = None,
100
182
  image: typing.Optional[modal.image._Image] = None,
101
- secrets: collections.abc.Sequence[modal.secret._Secret] = (),
183
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
184
+ secrets: typing.Optional[collections.abc.Collection[modal.secret._Secret]] = None,
102
185
  mounts: collections.abc.Sequence[modal.mount._Mount] = (),
103
186
  network_file_systems: dict[typing.Union[str, os.PathLike], modal.network_file_system._NetworkFileSystem] = {},
104
- timeout: typing.Optional[int] = None,
187
+ timeout: int = 300,
188
+ idle_timeout: typing.Optional[int] = None,
105
189
  workdir: typing.Optional[str] = None,
106
190
  gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
107
191
  cloud: typing.Optional[str] = None,
@@ -114,90 +198,284 @@ class _Sandbox(modal._object._Object):
114
198
  typing.Union[str, os.PathLike],
115
199
  typing.Union[modal.volume._Volume, modal.cloud_bucket_mount._CloudBucketMount],
116
200
  ] = {},
117
- pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
201
+ pty: bool = False,
118
202
  encrypted_ports: collections.abc.Sequence[int] = [],
203
+ h2_ports: collections.abc.Sequence[int] = [],
119
204
  unencrypted_ports: collections.abc.Sequence[int] = [],
120
205
  proxy: typing.Optional[modal.proxy._Proxy] = None,
206
+ experimental_options: typing.Optional[dict[str, bool]] = None,
121
207
  _experimental_enable_snapshot: bool = False,
122
208
  _experimental_scheduler_placement: typing.Optional[modal.scheduler_placement.SchedulerPlacement] = None,
123
209
  client: typing.Optional[modal.client._Client] = None,
124
- ): ...
210
+ verbose: bool = False,
211
+ pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
212
+ ):
213
+ """Private method used internally.
214
+
215
+ This method exposes some internal arguments (currently `mounts`) which are not in the public API.
216
+ `mounts` is currently only used by modal shell (cli) to provide a function's mounts to the
217
+ sandbox that runs the shell session.
218
+ """
219
+ ...
220
+
125
221
  def _hydrate_metadata(self, handle_metadata: typing.Optional[google.protobuf.message.Message]): ...
126
222
  @staticmethod
127
- async def from_id(sandbox_id: str, client: typing.Optional[modal.client._Client] = None) -> _Sandbox: ...
128
- async def set_tags(self, tags: dict[str, str], *, client: typing.Optional[modal.client._Client] = None): ...
129
- async def snapshot_filesystem(self, timeout: int = 55) -> modal.image._Image: ...
130
- async def wait(self, raise_on_termination: bool = True): ...
131
- async def tunnels(self, timeout: int = 50) -> dict[int, modal._tunnel.Tunnel]: ...
132
- async def terminate(self) -> None: ...
133
- async def poll(self) -> typing.Optional[int]: ...
223
+ async def from_name(
224
+ app_name: str,
225
+ name: str,
226
+ *,
227
+ environment_name: typing.Optional[str] = None,
228
+ client: typing.Optional[modal.client._Client] = None,
229
+ ) -> _Sandbox:
230
+ """Get a running Sandbox by name from a deployed App.
231
+
232
+ Raises a modal.exception.NotFoundError if no running sandbox is found with the given name.
233
+ A Sandbox's name is the `name` argument passed to `Sandbox.create`.
234
+ """
235
+ ...
236
+
237
+ @staticmethod
238
+ async def from_id(sandbox_id: str, client: typing.Optional[modal.client._Client] = None) -> _Sandbox:
239
+ """Construct a Sandbox from an id and look up the Sandbox result.
240
+
241
+ The ID of a Sandbox object can be accessed using `.object_id`.
242
+ """
243
+ ...
244
+
245
+ async def get_tags(self) -> dict[str, str]:
246
+ """Fetches any tags (key-value pairs) currently attached to this Sandbox from the server."""
247
+ ...
248
+
249
+ async def set_tags(self, tags: dict[str, str], *, client: typing.Optional[modal.client._Client] = None) -> None:
250
+ """Set tags (key-value pairs) on the Sandbox. Tags can be used to filter results in `Sandbox.list`."""
251
+ ...
252
+
253
+ async def snapshot_filesystem(self, timeout: int = 55) -> modal.image._Image:
254
+ """Snapshot the filesystem of the Sandbox.
255
+
256
+ Returns an [`Image`](https://modal.com/docs/reference/modal.Image) object which
257
+ can be used to spawn a new Sandbox with the same filesystem.
258
+ """
259
+ ...
260
+
261
+ async def wait(self, raise_on_termination: bool = True):
262
+ """Wait for the Sandbox to finish running."""
263
+ ...
264
+
265
+ async def tunnels(self, timeout: int = 50) -> dict[int, modal._tunnel.Tunnel]:
266
+ """Get Tunnel metadata for the sandbox.
267
+
268
+ Raises `SandboxTimeoutError` if the tunnels are not available after the timeout.
269
+
270
+ Returns a dictionary of `Tunnel` objects which are keyed by the container port.
271
+
272
+ NOTE: Previous to client [v0.64.153](https://modal.com/docs/reference/changelog#064153-2024-09-30), this
273
+ returned a list of `TunnelData` objects.
274
+ """
275
+ ...
276
+
277
+ async def create_connect_token(
278
+ self, user_metadata: typing.Union[str, dict[str, typing.Any], None] = None
279
+ ) -> SandboxConnectCredentials:
280
+ """[Alpha] Create a token for making HTTP connections to the Sandbox.
281
+
282
+ Also accepts an optional user_metadata string or dict to associate with the token. This metadata
283
+ will be added to the headers by the proxy when forwarding requests to the Sandbox.
284
+ """
285
+ ...
286
+
287
+ async def reload_volumes(self) -> None:
288
+ """Reload all Volumes mounted in the Sandbox.
289
+
290
+ Added in v1.1.0.
291
+ """
292
+ ...
293
+
294
+ async def terminate(self) -> None:
295
+ """Terminate Sandbox execution.
296
+
297
+ This is a no-op if the Sandbox has already finished running.
298
+ """
299
+ ...
300
+
301
+ async def poll(self) -> typing.Optional[int]:
302
+ """Check if the Sandbox has finished running.
303
+
304
+ Returns `None` if the Sandbox is still running, else returns the exit code.
305
+ """
306
+ ...
307
+
134
308
  async def _get_task_id(self) -> str: ...
309
+ async def _get_command_router_client(
310
+ self, task_id: str
311
+ ) -> typing.Optional[modal._utils.task_command_router_client.TaskCommandRouterClient]: ...
135
312
  @typing.overload
136
313
  async def exec(
137
314
  self,
138
- *cmds: str,
139
- pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
315
+ *args: str,
140
316
  stdout: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
141
317
  stderr: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
142
318
  timeout: typing.Optional[int] = None,
143
319
  workdir: typing.Optional[str] = None,
144
- secrets: collections.abc.Sequence[modal.secret._Secret] = (),
320
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
321
+ secrets: typing.Optional[collections.abc.Collection[modal.secret._Secret]] = None,
145
322
  text: typing.Literal[True] = True,
146
323
  bufsize: typing.Literal[-1, 1] = -1,
324
+ pty: bool = False,
325
+ pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
147
326
  _pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
148
327
  ) -> modal.container_process._ContainerProcess[str]: ...
149
328
  @typing.overload
150
329
  async def exec(
151
330
  self,
152
- *cmds: str,
153
- pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
331
+ *args: str,
154
332
  stdout: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
155
333
  stderr: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
156
334
  timeout: typing.Optional[int] = None,
157
335
  workdir: typing.Optional[str] = None,
158
- secrets: collections.abc.Sequence[modal.secret._Secret] = (),
336
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
337
+ secrets: typing.Optional[collections.abc.Collection[modal.secret._Secret]] = None,
159
338
  text: typing.Literal[False] = False,
160
339
  bufsize: typing.Literal[-1, 1] = -1,
340
+ pty: bool = False,
341
+ pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
161
342
  _pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
162
343
  ) -> modal.container_process._ContainerProcess[bytes]: ...
344
+ async def _exec(
345
+ self,
346
+ *args: str,
347
+ pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
348
+ stdout: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
349
+ stderr: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
350
+ timeout: typing.Optional[int] = None,
351
+ workdir: typing.Optional[str] = None,
352
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
353
+ secrets: typing.Optional[collections.abc.Collection[modal.secret._Secret]] = None,
354
+ text: bool = True,
355
+ bufsize: typing.Literal[-1, 1] = -1,
356
+ ) -> typing.Union[modal.container_process._ContainerProcess[bytes], modal.container_process._ContainerProcess[str]]:
357
+ """Private method used internally.
358
+
359
+ This method exposes some internal arguments (currently `pty_info`) which are not in the public API.
360
+ """
361
+ ...
362
+
363
+ async def _exec_through_server(
364
+ self,
365
+ *args: str,
366
+ task_id: str,
367
+ pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
368
+ stdout: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
369
+ stderr: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
370
+ timeout: typing.Optional[int] = None,
371
+ workdir: typing.Optional[str] = None,
372
+ secret_ids: typing.Optional[collections.abc.Collection[str]] = None,
373
+ text: bool = True,
374
+ bufsize: typing.Literal[-1, 1] = -1,
375
+ runtime_debug: bool = False,
376
+ ) -> typing.Union[modal.container_process._ContainerProcess[bytes], modal.container_process._ContainerProcess[str]]:
377
+ """Execute a command through the Modal server."""
378
+ ...
379
+
380
+ async def _exec_through_command_router(
381
+ self,
382
+ *args: str,
383
+ task_id: str,
384
+ command_router_client: modal._utils.task_command_router_client.TaskCommandRouterClient,
385
+ pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
386
+ stdout: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
387
+ stderr: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
388
+ timeout: typing.Optional[int] = None,
389
+ workdir: typing.Optional[str] = None,
390
+ secret_ids: typing.Optional[collections.abc.Collection[str]] = None,
391
+ text: bool = True,
392
+ bufsize: typing.Literal[-1, 1] = -1,
393
+ runtime_debug: bool = False,
394
+ ) -> typing.Union[modal.container_process._ContainerProcess[bytes], modal.container_process._ContainerProcess[str]]:
395
+ """Execute a command through a task command router running on the Modal worker."""
396
+ ...
397
+
163
398
  async def _experimental_snapshot(self) -> modal.snapshot._SandboxSnapshot: ...
164
399
  @staticmethod
165
400
  async def _experimental_from_snapshot(
166
- snapshot: modal.snapshot._SandboxSnapshot, client: typing.Optional[modal.client._Client] = None
401
+ snapshot: modal.snapshot._SandboxSnapshot,
402
+ client: typing.Optional[modal.client._Client] = None,
403
+ *,
404
+ name: typing.Optional[str] = _DEFAULT_SANDBOX_NAME_OVERRIDE,
167
405
  ): ...
168
406
  @typing.overload
169
407
  async def open(self, path: str, mode: _typeshed.OpenTextMode) -> modal.file_io._FileIO[str]: ...
170
408
  @typing.overload
171
409
  async def open(self, path: str, mode: _typeshed.OpenBinaryMode) -> modal.file_io._FileIO[bytes]: ...
172
- async def ls(self, path: str) -> list[str]: ...
173
- async def mkdir(self, path: str, parents: bool = False) -> None: ...
174
- async def rm(self, path: str, recursive: bool = False) -> None: ...
410
+ async def ls(self, path: str) -> list[str]:
411
+ """[Alpha] List the contents of a directory in the Sandbox."""
412
+ ...
413
+
414
+ async def mkdir(self, path: str, parents: bool = False) -> None:
415
+ """[Alpha] Create a new directory in the Sandbox."""
416
+ ...
417
+
418
+ async def rm(self, path: str, recursive: bool = False) -> None:
419
+ """[Alpha] Remove a file or directory in the Sandbox."""
420
+ ...
421
+
175
422
  def watch(
176
423
  self,
177
424
  path: str,
178
425
  filter: typing.Optional[list[modal.file_io.FileWatchEventType]] = None,
179
426
  recursive: typing.Optional[bool] = None,
180
427
  timeout: typing.Optional[int] = None,
181
- ) -> typing.AsyncIterator[modal.file_io.FileWatchEvent]: ...
428
+ ) -> typing.AsyncIterator[modal.file_io.FileWatchEvent]:
429
+ """[Alpha] Watch a file or directory in the Sandbox for changes."""
430
+ ...
431
+
182
432
  @property
183
- def stdout(self) -> modal.io_streams._StreamReader[str]: ...
433
+ def stdout(self) -> modal.io_streams._StreamReader[str]:
434
+ """[`StreamReader`](https://modal.com/docs/reference/modal.io_streams#modalio_streamsstreamreader) for
435
+ the sandbox's stdout stream.
436
+ """
437
+ ...
438
+
184
439
  @property
185
- def stderr(self) -> modal.io_streams._StreamReader[str]: ...
440
+ def stderr(self) -> modal.io_streams._StreamReader[str]:
441
+ """[`StreamReader`](https://modal.com/docs/reference/modal.io_streams#modalio_streamsstreamreader) for
442
+ the Sandbox's stderr stream.
443
+ """
444
+ ...
445
+
186
446
  @property
187
- def stdin(self) -> modal.io_streams._StreamWriter: ...
447
+ def stdin(self) -> modal.io_streams._StreamWriter:
448
+ """[`StreamWriter`](https://modal.com/docs/reference/modal.io_streams#modalio_streamsstreamwriter) for
449
+ the Sandbox's stdin stream.
450
+ """
451
+ ...
452
+
188
453
  @property
189
- def returncode(self) -> typing.Optional[int]: ...
454
+ def returncode(self) -> typing.Optional[int]:
455
+ """Return code of the Sandbox process if it has finished running, else `None`."""
456
+ ...
457
+
190
458
  @staticmethod
191
459
  def list(
192
460
  *,
193
461
  app_id: typing.Optional[str] = None,
194
462
  tags: typing.Optional[dict[str, str]] = None,
195
463
  client: typing.Optional[modal.client._Client] = None,
196
- ) -> collections.abc.AsyncGenerator[_Sandbox, None]: ...
464
+ ) -> collections.abc.AsyncGenerator[_Sandbox, None]:
465
+ """List all Sandboxes for the current Environment or App ID (if specified). If tags are specified, only
466
+ Sandboxes that have at least those tags are returned. Returns an iterator over `Sandbox` objects.
467
+ """
468
+ ...
197
469
 
198
470
  SUPERSELF = typing.TypeVar("SUPERSELF", covariant=True)
199
471
 
200
472
  class Sandbox(modal.object.Object):
473
+ """A `Sandbox` object lets you interact with a running sandbox. This API is similar to Python's
474
+ [asyncio.subprocess.Process](https://docs.python.org/3/library/asyncio-subprocess.html#asyncio.subprocess.Process).
475
+
476
+ Refer to the [guide](https://modal.com/docs/guide/sandbox) on how to spawn and use sandboxes.
477
+ """
478
+
201
479
  _result: typing.Optional[modal_proto.api_pb2.GenericResult]
202
480
  _stdout: modal.io_streams.StreamReader[str]
203
481
  _stderr: modal.io_streams.StreamReader[str]
@@ -205,14 +483,22 @@ class Sandbox(modal.object.Object):
205
483
  _task_id: typing.Optional[str]
206
484
  _tunnels: typing.Optional[dict[int, modal._tunnel.Tunnel]]
207
485
  _enable_snapshot: bool
486
+ _command_router_client: typing.Optional[modal._utils.task_command_router_client.TaskCommandRouterClient]
487
+
488
+ def __init__(self, *args, **kwargs):
489
+ """mdmd:hidden"""
490
+ ...
208
491
 
209
- def __init__(self, *args, **kwargs): ...
492
+ @staticmethod
493
+ def _default_pty_info() -> modal_proto.api_pb2.PTYInfo: ...
210
494
  @staticmethod
211
495
  def _new(
212
- entrypoint_args: collections.abc.Sequence[str],
496
+ args: collections.abc.Sequence[str],
213
497
  image: modal.image.Image,
214
- secrets: collections.abc.Sequence[modal.secret.Secret],
215
- timeout: typing.Optional[int] = None,
498
+ secrets: collections.abc.Collection[modal.secret.Secret],
499
+ name: typing.Optional[str] = None,
500
+ timeout: int = 300,
501
+ idle_timeout: typing.Optional[int] = None,
216
502
  workdir: typing.Optional[str] = None,
217
503
  gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
218
504
  cloud: typing.Optional[str] = None,
@@ -226,27 +512,35 @@ class Sandbox(modal.object.Object):
226
512
  volumes: dict[
227
513
  typing.Union[str, os.PathLike], typing.Union[modal.volume.Volume, modal.cloud_bucket_mount.CloudBucketMount]
228
514
  ] = {},
515
+ pty: bool = False,
229
516
  pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
230
517
  encrypted_ports: collections.abc.Sequence[int] = [],
518
+ h2_ports: collections.abc.Sequence[int] = [],
231
519
  unencrypted_ports: collections.abc.Sequence[int] = [],
232
520
  proxy: typing.Optional[modal.proxy.Proxy] = None,
521
+ experimental_options: typing.Optional[dict[str, bool]] = None,
233
522
  _experimental_scheduler_placement: typing.Optional[modal.scheduler_placement.SchedulerPlacement] = None,
234
523
  enable_snapshot: bool = False,
235
- ) -> Sandbox: ...
524
+ verbose: bool = False,
525
+ ) -> Sandbox:
526
+ """mdmd:hidden"""
527
+ ...
236
528
 
237
529
  class __create_spec(typing_extensions.Protocol):
238
530
  def __call__(
239
531
  self,
240
532
  /,
241
- *entrypoint_args: str,
533
+ *args: str,
242
534
  app: typing.Optional[modal.app.App] = None,
243
- environment_name: typing.Optional[str] = None,
535
+ name: typing.Optional[str] = None,
244
536
  image: typing.Optional[modal.image.Image] = None,
245
- secrets: collections.abc.Sequence[modal.secret.Secret] = (),
537
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
538
+ secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
246
539
  network_file_systems: dict[
247
540
  typing.Union[str, os.PathLike], modal.network_file_system.NetworkFileSystem
248
541
  ] = {},
249
- timeout: typing.Optional[int] = None,
542
+ timeout: int = 300,
543
+ idle_timeout: typing.Optional[int] = None,
250
544
  workdir: typing.Optional[str] = None,
251
545
  gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
252
546
  cloud: typing.Optional[str] = None,
@@ -259,26 +553,48 @@ class Sandbox(modal.object.Object):
259
553
  typing.Union[str, os.PathLike],
260
554
  typing.Union[modal.volume.Volume, modal.cloud_bucket_mount.CloudBucketMount],
261
555
  ] = {},
262
- pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
556
+ pty: bool = False,
263
557
  encrypted_ports: collections.abc.Sequence[int] = [],
558
+ h2_ports: collections.abc.Sequence[int] = [],
264
559
  unencrypted_ports: collections.abc.Sequence[int] = [],
265
560
  proxy: typing.Optional[modal.proxy.Proxy] = None,
561
+ verbose: bool = False,
562
+ experimental_options: typing.Optional[dict[str, bool]] = None,
266
563
  _experimental_enable_snapshot: bool = False,
267
564
  _experimental_scheduler_placement: typing.Optional[modal.scheduler_placement.SchedulerPlacement] = None,
268
565
  client: typing.Optional[modal.client.Client] = None,
269
- ) -> Sandbox: ...
566
+ environment_name: typing.Optional[str] = None,
567
+ pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
568
+ ) -> Sandbox:
569
+ """Create a new Sandbox to run untrusted, arbitrary code.
570
+
571
+ The Sandbox's corresponding container will be created asynchronously.
572
+
573
+ **Usage**
574
+
575
+ ```python
576
+ app = modal.App.lookup('sandbox-hello-world', create_if_missing=True)
577
+ sandbox = modal.Sandbox.create("echo", "hello world", app=app)
578
+ print(sandbox.stdout.read())
579
+ sandbox.wait()
580
+ ```
581
+ """
582
+ ...
583
+
270
584
  async def aio(
271
585
  self,
272
586
  /,
273
- *entrypoint_args: str,
587
+ *args: str,
274
588
  app: typing.Optional[modal.app.App] = None,
275
- environment_name: typing.Optional[str] = None,
589
+ name: typing.Optional[str] = None,
276
590
  image: typing.Optional[modal.image.Image] = None,
277
- secrets: collections.abc.Sequence[modal.secret.Secret] = (),
591
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
592
+ secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
278
593
  network_file_systems: dict[
279
594
  typing.Union[str, os.PathLike], modal.network_file_system.NetworkFileSystem
280
595
  ] = {},
281
- timeout: typing.Optional[int] = None,
596
+ timeout: int = 300,
597
+ idle_timeout: typing.Optional[int] = None,
282
598
  workdir: typing.Optional[str] = None,
283
599
  gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
284
600
  cloud: typing.Optional[str] = None,
@@ -291,14 +607,33 @@ class Sandbox(modal.object.Object):
291
607
  typing.Union[str, os.PathLike],
292
608
  typing.Union[modal.volume.Volume, modal.cloud_bucket_mount.CloudBucketMount],
293
609
  ] = {},
294
- pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
610
+ pty: bool = False,
295
611
  encrypted_ports: collections.abc.Sequence[int] = [],
612
+ h2_ports: collections.abc.Sequence[int] = [],
296
613
  unencrypted_ports: collections.abc.Sequence[int] = [],
297
614
  proxy: typing.Optional[modal.proxy.Proxy] = None,
615
+ verbose: bool = False,
616
+ experimental_options: typing.Optional[dict[str, bool]] = None,
298
617
  _experimental_enable_snapshot: bool = False,
299
618
  _experimental_scheduler_placement: typing.Optional[modal.scheduler_placement.SchedulerPlacement] = None,
300
619
  client: typing.Optional[modal.client.Client] = None,
301
- ) -> Sandbox: ...
620
+ environment_name: typing.Optional[str] = None,
621
+ pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
622
+ ) -> Sandbox:
623
+ """Create a new Sandbox to run untrusted, arbitrary code.
624
+
625
+ The Sandbox's corresponding container will be created asynchronously.
626
+
627
+ **Usage**
628
+
629
+ ```python
630
+ app = modal.App.lookup('sandbox-hello-world', create_if_missing=True)
631
+ sandbox = modal.Sandbox.create("echo", "hello world", app=app)
632
+ print(sandbox.stdout.read())
633
+ sandbox.wait()
634
+ ```
635
+ """
636
+ ...
302
637
 
303
638
  create: __create_spec
304
639
 
@@ -306,16 +641,18 @@ class Sandbox(modal.object.Object):
306
641
  def __call__(
307
642
  self,
308
643
  /,
309
- *entrypoint_args: str,
644
+ *args: str,
310
645
  app: typing.Optional[modal.app.App] = None,
311
- environment_name: typing.Optional[str] = None,
646
+ name: typing.Optional[str] = None,
312
647
  image: typing.Optional[modal.image.Image] = None,
313
- secrets: collections.abc.Sequence[modal.secret.Secret] = (),
648
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
649
+ secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
314
650
  mounts: collections.abc.Sequence[modal.mount.Mount] = (),
315
651
  network_file_systems: dict[
316
652
  typing.Union[str, os.PathLike], modal.network_file_system.NetworkFileSystem
317
653
  ] = {},
318
- timeout: typing.Optional[int] = None,
654
+ timeout: int = 300,
655
+ idle_timeout: typing.Optional[int] = None,
319
656
  workdir: typing.Optional[str] = None,
320
657
  gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
321
658
  cloud: typing.Optional[str] = None,
@@ -328,27 +665,41 @@ class Sandbox(modal.object.Object):
328
665
  typing.Union[str, os.PathLike],
329
666
  typing.Union[modal.volume.Volume, modal.cloud_bucket_mount.CloudBucketMount],
330
667
  ] = {},
331
- pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
668
+ pty: bool = False,
332
669
  encrypted_ports: collections.abc.Sequence[int] = [],
670
+ h2_ports: collections.abc.Sequence[int] = [],
333
671
  unencrypted_ports: collections.abc.Sequence[int] = [],
334
672
  proxy: typing.Optional[modal.proxy.Proxy] = None,
673
+ experimental_options: typing.Optional[dict[str, bool]] = None,
335
674
  _experimental_enable_snapshot: bool = False,
336
675
  _experimental_scheduler_placement: typing.Optional[modal.scheduler_placement.SchedulerPlacement] = None,
337
676
  client: typing.Optional[modal.client.Client] = None,
338
- ): ...
677
+ verbose: bool = False,
678
+ pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
679
+ ):
680
+ """Private method used internally.
681
+
682
+ This method exposes some internal arguments (currently `mounts`) which are not in the public API.
683
+ `mounts` is currently only used by modal shell (cli) to provide a function's mounts to the
684
+ sandbox that runs the shell session.
685
+ """
686
+ ...
687
+
339
688
  async def aio(
340
689
  self,
341
690
  /,
342
- *entrypoint_args: str,
691
+ *args: str,
343
692
  app: typing.Optional[modal.app.App] = None,
344
- environment_name: typing.Optional[str] = None,
693
+ name: typing.Optional[str] = None,
345
694
  image: typing.Optional[modal.image.Image] = None,
346
- secrets: collections.abc.Sequence[modal.secret.Secret] = (),
695
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
696
+ secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
347
697
  mounts: collections.abc.Sequence[modal.mount.Mount] = (),
348
698
  network_file_systems: dict[
349
699
  typing.Union[str, os.PathLike], modal.network_file_system.NetworkFileSystem
350
700
  ] = {},
351
- timeout: typing.Optional[int] = None,
701
+ timeout: int = 300,
702
+ idle_timeout: typing.Optional[int] = None,
352
703
  workdir: typing.Optional[str] = None,
353
704
  gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
354
705
  cloud: typing.Optional[str] = None,
@@ -361,58 +712,232 @@ class Sandbox(modal.object.Object):
361
712
  typing.Union[str, os.PathLike],
362
713
  typing.Union[modal.volume.Volume, modal.cloud_bucket_mount.CloudBucketMount],
363
714
  ] = {},
364
- pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
715
+ pty: bool = False,
365
716
  encrypted_ports: collections.abc.Sequence[int] = [],
717
+ h2_ports: collections.abc.Sequence[int] = [],
366
718
  unencrypted_ports: collections.abc.Sequence[int] = [],
367
719
  proxy: typing.Optional[modal.proxy.Proxy] = None,
720
+ experimental_options: typing.Optional[dict[str, bool]] = None,
368
721
  _experimental_enable_snapshot: bool = False,
369
722
  _experimental_scheduler_placement: typing.Optional[modal.scheduler_placement.SchedulerPlacement] = None,
370
723
  client: typing.Optional[modal.client.Client] = None,
371
- ): ...
724
+ verbose: bool = False,
725
+ pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
726
+ ):
727
+ """Private method used internally.
728
+
729
+ This method exposes some internal arguments (currently `mounts`) which are not in the public API.
730
+ `mounts` is currently only used by modal shell (cli) to provide a function's mounts to the
731
+ sandbox that runs the shell session.
732
+ """
733
+ ...
372
734
 
373
735
  _create: ___create_spec
374
736
 
375
737
  def _hydrate_metadata(self, handle_metadata: typing.Optional[google.protobuf.message.Message]): ...
376
738
 
739
+ class __from_name_spec(typing_extensions.Protocol):
740
+ def __call__(
741
+ self,
742
+ /,
743
+ app_name: str,
744
+ name: str,
745
+ *,
746
+ environment_name: typing.Optional[str] = None,
747
+ client: typing.Optional[modal.client.Client] = None,
748
+ ) -> Sandbox:
749
+ """Get a running Sandbox by name from a deployed App.
750
+
751
+ Raises a modal.exception.NotFoundError if no running sandbox is found with the given name.
752
+ A Sandbox's name is the `name` argument passed to `Sandbox.create`.
753
+ """
754
+ ...
755
+
756
+ async def aio(
757
+ self,
758
+ /,
759
+ app_name: str,
760
+ name: str,
761
+ *,
762
+ environment_name: typing.Optional[str] = None,
763
+ client: typing.Optional[modal.client.Client] = None,
764
+ ) -> Sandbox:
765
+ """Get a running Sandbox by name from a deployed App.
766
+
767
+ Raises a modal.exception.NotFoundError if no running sandbox is found with the given name.
768
+ A Sandbox's name is the `name` argument passed to `Sandbox.create`.
769
+ """
770
+ ...
771
+
772
+ from_name: __from_name_spec
773
+
377
774
  class __from_id_spec(typing_extensions.Protocol):
378
- def __call__(self, /, sandbox_id: str, client: typing.Optional[modal.client.Client] = None) -> Sandbox: ...
379
- async def aio(self, /, sandbox_id: str, client: typing.Optional[modal.client.Client] = None) -> Sandbox: ...
775
+ def __call__(self, /, sandbox_id: str, client: typing.Optional[modal.client.Client] = None) -> Sandbox:
776
+ """Construct a Sandbox from an id and look up the Sandbox result.
777
+
778
+ The ID of a Sandbox object can be accessed using `.object_id`.
779
+ """
780
+ ...
781
+
782
+ async def aio(self, /, sandbox_id: str, client: typing.Optional[modal.client.Client] = None) -> Sandbox:
783
+ """Construct a Sandbox from an id and look up the Sandbox result.
784
+
785
+ The ID of a Sandbox object can be accessed using `.object_id`.
786
+ """
787
+ ...
380
788
 
381
789
  from_id: __from_id_spec
382
790
 
791
+ class __get_tags_spec(typing_extensions.Protocol[SUPERSELF]):
792
+ def __call__(self, /) -> dict[str, str]:
793
+ """Fetches any tags (key-value pairs) currently attached to this Sandbox from the server."""
794
+ ...
795
+
796
+ async def aio(self, /) -> dict[str, str]:
797
+ """Fetches any tags (key-value pairs) currently attached to this Sandbox from the server."""
798
+ ...
799
+
800
+ get_tags: __get_tags_spec[typing_extensions.Self]
801
+
383
802
  class __set_tags_spec(typing_extensions.Protocol[SUPERSELF]):
384
- def __call__(self, /, tags: dict[str, str], *, client: typing.Optional[modal.client.Client] = None): ...
385
- async def aio(self, /, tags: dict[str, str], *, client: typing.Optional[modal.client.Client] = None): ...
803
+ def __call__(self, /, tags: dict[str, str], *, client: typing.Optional[modal.client.Client] = None) -> None:
804
+ """Set tags (key-value pairs) on the Sandbox. Tags can be used to filter results in `Sandbox.list`."""
805
+ ...
806
+
807
+ async def aio(self, /, tags: dict[str, str], *, client: typing.Optional[modal.client.Client] = None) -> None:
808
+ """Set tags (key-value pairs) on the Sandbox. Tags can be used to filter results in `Sandbox.list`."""
809
+ ...
386
810
 
387
811
  set_tags: __set_tags_spec[typing_extensions.Self]
388
812
 
389
813
  class __snapshot_filesystem_spec(typing_extensions.Protocol[SUPERSELF]):
390
- def __call__(self, /, timeout: int = 55) -> modal.image.Image: ...
391
- async def aio(self, /, timeout: int = 55) -> modal.image.Image: ...
814
+ def __call__(self, /, timeout: int = 55) -> modal.image.Image:
815
+ """Snapshot the filesystem of the Sandbox.
816
+
817
+ Returns an [`Image`](https://modal.com/docs/reference/modal.Image) object which
818
+ can be used to spawn a new Sandbox with the same filesystem.
819
+ """
820
+ ...
821
+
822
+ async def aio(self, /, timeout: int = 55) -> modal.image.Image:
823
+ """Snapshot the filesystem of the Sandbox.
824
+
825
+ Returns an [`Image`](https://modal.com/docs/reference/modal.Image) object which
826
+ can be used to spawn a new Sandbox with the same filesystem.
827
+ """
828
+ ...
392
829
 
393
830
  snapshot_filesystem: __snapshot_filesystem_spec[typing_extensions.Self]
394
831
 
395
832
  class __wait_spec(typing_extensions.Protocol[SUPERSELF]):
396
- def __call__(self, /, raise_on_termination: bool = True): ...
397
- async def aio(self, /, raise_on_termination: bool = True): ...
833
+ def __call__(self, /, raise_on_termination: bool = True):
834
+ """Wait for the Sandbox to finish running."""
835
+ ...
836
+
837
+ async def aio(self, /, raise_on_termination: bool = True):
838
+ """Wait for the Sandbox to finish running."""
839
+ ...
398
840
 
399
841
  wait: __wait_spec[typing_extensions.Self]
400
842
 
401
843
  class __tunnels_spec(typing_extensions.Protocol[SUPERSELF]):
402
- def __call__(self, /, timeout: int = 50) -> dict[int, modal._tunnel.Tunnel]: ...
403
- async def aio(self, /, timeout: int = 50) -> dict[int, modal._tunnel.Tunnel]: ...
844
+ def __call__(self, /, timeout: int = 50) -> dict[int, modal._tunnel.Tunnel]:
845
+ """Get Tunnel metadata for the sandbox.
846
+
847
+ Raises `SandboxTimeoutError` if the tunnels are not available after the timeout.
848
+
849
+ Returns a dictionary of `Tunnel` objects which are keyed by the container port.
850
+
851
+ NOTE: Previous to client [v0.64.153](https://modal.com/docs/reference/changelog#064153-2024-09-30), this
852
+ returned a list of `TunnelData` objects.
853
+ """
854
+ ...
855
+
856
+ async def aio(self, /, timeout: int = 50) -> dict[int, modal._tunnel.Tunnel]:
857
+ """Get Tunnel metadata for the sandbox.
858
+
859
+ Raises `SandboxTimeoutError` if the tunnels are not available after the timeout.
860
+
861
+ Returns a dictionary of `Tunnel` objects which are keyed by the container port.
862
+
863
+ NOTE: Previous to client [v0.64.153](https://modal.com/docs/reference/changelog#064153-2024-09-30), this
864
+ returned a list of `TunnelData` objects.
865
+ """
866
+ ...
404
867
 
405
868
  tunnels: __tunnels_spec[typing_extensions.Self]
406
869
 
870
+ class __create_connect_token_spec(typing_extensions.Protocol[SUPERSELF]):
871
+ def __call__(
872
+ self, /, user_metadata: typing.Union[str, dict[str, typing.Any], None] = None
873
+ ) -> SandboxConnectCredentials:
874
+ """[Alpha] Create a token for making HTTP connections to the Sandbox.
875
+
876
+ Also accepts an optional user_metadata string or dict to associate with the token. This metadata
877
+ will be added to the headers by the proxy when forwarding requests to the Sandbox.
878
+ """
879
+ ...
880
+
881
+ async def aio(
882
+ self, /, user_metadata: typing.Union[str, dict[str, typing.Any], None] = None
883
+ ) -> SandboxConnectCredentials:
884
+ """[Alpha] Create a token for making HTTP connections to the Sandbox.
885
+
886
+ Also accepts an optional user_metadata string or dict to associate with the token. This metadata
887
+ will be added to the headers by the proxy when forwarding requests to the Sandbox.
888
+ """
889
+ ...
890
+
891
+ create_connect_token: __create_connect_token_spec[typing_extensions.Self]
892
+
893
+ class __reload_volumes_spec(typing_extensions.Protocol[SUPERSELF]):
894
+ def __call__(self, /) -> None:
895
+ """Reload all Volumes mounted in the Sandbox.
896
+
897
+ Added in v1.1.0.
898
+ """
899
+ ...
900
+
901
+ async def aio(self, /) -> None:
902
+ """Reload all Volumes mounted in the Sandbox.
903
+
904
+ Added in v1.1.0.
905
+ """
906
+ ...
907
+
908
+ reload_volumes: __reload_volumes_spec[typing_extensions.Self]
909
+
407
910
  class __terminate_spec(typing_extensions.Protocol[SUPERSELF]):
408
- def __call__(self, /) -> None: ...
409
- async def aio(self, /) -> None: ...
911
+ def __call__(self, /) -> None:
912
+ """Terminate Sandbox execution.
913
+
914
+ This is a no-op if the Sandbox has already finished running.
915
+ """
916
+ ...
917
+
918
+ async def aio(self, /) -> None:
919
+ """Terminate Sandbox execution.
920
+
921
+ This is a no-op if the Sandbox has already finished running.
922
+ """
923
+ ...
410
924
 
411
925
  terminate: __terminate_spec[typing_extensions.Self]
412
926
 
413
927
  class __poll_spec(typing_extensions.Protocol[SUPERSELF]):
414
- def __call__(self, /) -> typing.Optional[int]: ...
415
- async def aio(self, /) -> typing.Optional[int]: ...
928
+ def __call__(self, /) -> typing.Optional[int]:
929
+ """Check if the Sandbox has finished running.
930
+
931
+ Returns `None` if the Sandbox is still running, else returns the exit code.
932
+ """
933
+ ...
934
+
935
+ async def aio(self, /) -> typing.Optional[int]:
936
+ """Check if the Sandbox has finished running.
937
+
938
+ Returns `None` if the Sandbox is still running, else returns the exit code.
939
+ """
940
+ ...
416
941
 
417
942
  poll: __poll_spec[typing_extensions.Self]
418
943
 
@@ -422,70 +947,223 @@ class Sandbox(modal.object.Object):
422
947
 
423
948
  _get_task_id: ___get_task_id_spec[typing_extensions.Self]
424
949
 
950
+ class ___get_command_router_client_spec(typing_extensions.Protocol[SUPERSELF]):
951
+ def __call__(
952
+ self, /, task_id: str
953
+ ) -> typing.Optional[modal._utils.task_command_router_client.TaskCommandRouterClient]: ...
954
+ async def aio(
955
+ self, /, task_id: str
956
+ ) -> typing.Optional[modal._utils.task_command_router_client.TaskCommandRouterClient]: ...
957
+
958
+ _get_command_router_client: ___get_command_router_client_spec[typing_extensions.Self]
959
+
425
960
  class __exec_spec(typing_extensions.Protocol[SUPERSELF]):
426
961
  @typing.overload
427
962
  def __call__(
428
963
  self,
429
964
  /,
430
- *cmds: str,
431
- pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
965
+ *args: str,
432
966
  stdout: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
433
967
  stderr: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
434
968
  timeout: typing.Optional[int] = None,
435
969
  workdir: typing.Optional[str] = None,
436
- secrets: collections.abc.Sequence[modal.secret.Secret] = (),
970
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
971
+ secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
437
972
  text: typing.Literal[True] = True,
438
973
  bufsize: typing.Literal[-1, 1] = -1,
974
+ pty: bool = False,
975
+ pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
439
976
  _pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
440
977
  ) -> modal.container_process.ContainerProcess[str]: ...
441
978
  @typing.overload
442
979
  def __call__(
443
980
  self,
444
981
  /,
445
- *cmds: str,
446
- pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
982
+ *args: str,
447
983
  stdout: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
448
984
  stderr: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
449
985
  timeout: typing.Optional[int] = None,
450
986
  workdir: typing.Optional[str] = None,
451
- secrets: collections.abc.Sequence[modal.secret.Secret] = (),
987
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
988
+ secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
452
989
  text: typing.Literal[False] = False,
453
990
  bufsize: typing.Literal[-1, 1] = -1,
991
+ pty: bool = False,
992
+ pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
454
993
  _pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
455
994
  ) -> modal.container_process.ContainerProcess[bytes]: ...
456
995
  @typing.overload
457
996
  async def aio(
458
997
  self,
459
998
  /,
460
- *cmds: str,
461
- pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
999
+ *args: str,
462
1000
  stdout: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
463
1001
  stderr: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
464
1002
  timeout: typing.Optional[int] = None,
465
1003
  workdir: typing.Optional[str] = None,
466
- secrets: collections.abc.Sequence[modal.secret.Secret] = (),
1004
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
1005
+ secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
467
1006
  text: typing.Literal[True] = True,
468
1007
  bufsize: typing.Literal[-1, 1] = -1,
1008
+ pty: bool = False,
1009
+ pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
469
1010
  _pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
470
1011
  ) -> modal.container_process.ContainerProcess[str]: ...
471
1012
  @typing.overload
472
1013
  async def aio(
473
1014
  self,
474
1015
  /,
475
- *cmds: str,
476
- pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
1016
+ *args: str,
477
1017
  stdout: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
478
1018
  stderr: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
479
1019
  timeout: typing.Optional[int] = None,
480
1020
  workdir: typing.Optional[str] = None,
481
- secrets: collections.abc.Sequence[modal.secret.Secret] = (),
1021
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
1022
+ secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
482
1023
  text: typing.Literal[False] = False,
483
1024
  bufsize: typing.Literal[-1, 1] = -1,
1025
+ pty: bool = False,
1026
+ pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
484
1027
  _pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
485
1028
  ) -> modal.container_process.ContainerProcess[bytes]: ...
486
1029
 
487
1030
  exec: __exec_spec[typing_extensions.Self]
488
1031
 
1032
+ class ___exec_spec(typing_extensions.Protocol[SUPERSELF]):
1033
+ def __call__(
1034
+ self,
1035
+ /,
1036
+ *args: str,
1037
+ pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
1038
+ stdout: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
1039
+ stderr: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
1040
+ timeout: typing.Optional[int] = None,
1041
+ workdir: typing.Optional[str] = None,
1042
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
1043
+ secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
1044
+ text: bool = True,
1045
+ bufsize: typing.Literal[-1, 1] = -1,
1046
+ ) -> typing.Union[
1047
+ modal.container_process.ContainerProcess[bytes], modal.container_process.ContainerProcess[str]
1048
+ ]:
1049
+ """Private method used internally.
1050
+
1051
+ This method exposes some internal arguments (currently `pty_info`) which are not in the public API.
1052
+ """
1053
+ ...
1054
+
1055
+ async def aio(
1056
+ self,
1057
+ /,
1058
+ *args: str,
1059
+ pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
1060
+ stdout: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
1061
+ stderr: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
1062
+ timeout: typing.Optional[int] = None,
1063
+ workdir: typing.Optional[str] = None,
1064
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
1065
+ secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
1066
+ text: bool = True,
1067
+ bufsize: typing.Literal[-1, 1] = -1,
1068
+ ) -> typing.Union[
1069
+ modal.container_process.ContainerProcess[bytes], modal.container_process.ContainerProcess[str]
1070
+ ]:
1071
+ """Private method used internally.
1072
+
1073
+ This method exposes some internal arguments (currently `pty_info`) which are not in the public API.
1074
+ """
1075
+ ...
1076
+
1077
+ _exec: ___exec_spec[typing_extensions.Self]
1078
+
1079
+ class ___exec_through_server_spec(typing_extensions.Protocol[SUPERSELF]):
1080
+ def __call__(
1081
+ self,
1082
+ /,
1083
+ *args: str,
1084
+ task_id: str,
1085
+ pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
1086
+ stdout: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
1087
+ stderr: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
1088
+ timeout: typing.Optional[int] = None,
1089
+ workdir: typing.Optional[str] = None,
1090
+ secret_ids: typing.Optional[collections.abc.Collection[str]] = None,
1091
+ text: bool = True,
1092
+ bufsize: typing.Literal[-1, 1] = -1,
1093
+ runtime_debug: bool = False,
1094
+ ) -> typing.Union[
1095
+ modal.container_process.ContainerProcess[bytes], modal.container_process.ContainerProcess[str]
1096
+ ]:
1097
+ """Execute a command through the Modal server."""
1098
+ ...
1099
+
1100
+ async def aio(
1101
+ self,
1102
+ /,
1103
+ *args: str,
1104
+ task_id: str,
1105
+ pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
1106
+ stdout: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
1107
+ stderr: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
1108
+ timeout: typing.Optional[int] = None,
1109
+ workdir: typing.Optional[str] = None,
1110
+ secret_ids: typing.Optional[collections.abc.Collection[str]] = None,
1111
+ text: bool = True,
1112
+ bufsize: typing.Literal[-1, 1] = -1,
1113
+ runtime_debug: bool = False,
1114
+ ) -> typing.Union[
1115
+ modal.container_process.ContainerProcess[bytes], modal.container_process.ContainerProcess[str]
1116
+ ]:
1117
+ """Execute a command through the Modal server."""
1118
+ ...
1119
+
1120
+ _exec_through_server: ___exec_through_server_spec[typing_extensions.Self]
1121
+
1122
+ class ___exec_through_command_router_spec(typing_extensions.Protocol[SUPERSELF]):
1123
+ def __call__(
1124
+ self,
1125
+ /,
1126
+ *args: str,
1127
+ task_id: str,
1128
+ command_router_client: modal._utils.task_command_router_client.TaskCommandRouterClient,
1129
+ pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
1130
+ stdout: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
1131
+ stderr: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
1132
+ timeout: typing.Optional[int] = None,
1133
+ workdir: typing.Optional[str] = None,
1134
+ secret_ids: typing.Optional[collections.abc.Collection[str]] = None,
1135
+ text: bool = True,
1136
+ bufsize: typing.Literal[-1, 1] = -1,
1137
+ runtime_debug: bool = False,
1138
+ ) -> typing.Union[
1139
+ modal.container_process.ContainerProcess[bytes], modal.container_process.ContainerProcess[str]
1140
+ ]:
1141
+ """Execute a command through a task command router running on the Modal worker."""
1142
+ ...
1143
+
1144
+ async def aio(
1145
+ self,
1146
+ /,
1147
+ *args: str,
1148
+ task_id: str,
1149
+ command_router_client: modal._utils.task_command_router_client.TaskCommandRouterClient,
1150
+ pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
1151
+ stdout: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
1152
+ stderr: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
1153
+ timeout: typing.Optional[int] = None,
1154
+ workdir: typing.Optional[str] = None,
1155
+ secret_ids: typing.Optional[collections.abc.Collection[str]] = None,
1156
+ text: bool = True,
1157
+ bufsize: typing.Literal[-1, 1] = -1,
1158
+ runtime_debug: bool = False,
1159
+ ) -> typing.Union[
1160
+ modal.container_process.ContainerProcess[bytes], modal.container_process.ContainerProcess[str]
1161
+ ]:
1162
+ """Execute a command through a task command router running on the Modal worker."""
1163
+ ...
1164
+
1165
+ _exec_through_command_router: ___exec_through_command_router_spec[typing_extensions.Self]
1166
+
489
1167
  class ___experimental_snapshot_spec(typing_extensions.Protocol[SUPERSELF]):
490
1168
  def __call__(self, /) -> modal.snapshot.SandboxSnapshot: ...
491
1169
  async def aio(self, /) -> modal.snapshot.SandboxSnapshot: ...
@@ -494,10 +1172,20 @@ class Sandbox(modal.object.Object):
494
1172
 
495
1173
  class ___experimental_from_snapshot_spec(typing_extensions.Protocol):
496
1174
  def __call__(
497
- self, /, snapshot: modal.snapshot.SandboxSnapshot, client: typing.Optional[modal.client.Client] = None
1175
+ self,
1176
+ /,
1177
+ snapshot: modal.snapshot.SandboxSnapshot,
1178
+ client: typing.Optional[modal.client.Client] = None,
1179
+ *,
1180
+ name: typing.Optional[str] = _DEFAULT_SANDBOX_NAME_OVERRIDE,
498
1181
  ): ...
499
1182
  async def aio(
500
- self, /, snapshot: modal.snapshot.SandboxSnapshot, client: typing.Optional[modal.client.Client] = None
1183
+ self,
1184
+ /,
1185
+ snapshot: modal.snapshot.SandboxSnapshot,
1186
+ client: typing.Optional[modal.client.Client] = None,
1187
+ *,
1188
+ name: typing.Optional[str] = _DEFAULT_SANDBOX_NAME_OVERRIDE,
501
1189
  ): ...
502
1190
 
503
1191
  _experimental_from_snapshot: ___experimental_from_snapshot_spec
@@ -515,20 +1203,35 @@ class Sandbox(modal.object.Object):
515
1203
  open: __open_spec[typing_extensions.Self]
516
1204
 
517
1205
  class __ls_spec(typing_extensions.Protocol[SUPERSELF]):
518
- def __call__(self, /, path: str) -> list[str]: ...
519
- async def aio(self, /, path: str) -> list[str]: ...
1206
+ def __call__(self, /, path: str) -> list[str]:
1207
+ """[Alpha] List the contents of a directory in the Sandbox."""
1208
+ ...
1209
+
1210
+ async def aio(self, /, path: str) -> list[str]:
1211
+ """[Alpha] List the contents of a directory in the Sandbox."""
1212
+ ...
520
1213
 
521
1214
  ls: __ls_spec[typing_extensions.Self]
522
1215
 
523
1216
  class __mkdir_spec(typing_extensions.Protocol[SUPERSELF]):
524
- def __call__(self, /, path: str, parents: bool = False) -> None: ...
525
- async def aio(self, /, path: str, parents: bool = False) -> None: ...
1217
+ def __call__(self, /, path: str, parents: bool = False) -> None:
1218
+ """[Alpha] Create a new directory in the Sandbox."""
1219
+ ...
1220
+
1221
+ async def aio(self, /, path: str, parents: bool = False) -> None:
1222
+ """[Alpha] Create a new directory in the Sandbox."""
1223
+ ...
526
1224
 
527
1225
  mkdir: __mkdir_spec[typing_extensions.Self]
528
1226
 
529
1227
  class __rm_spec(typing_extensions.Protocol[SUPERSELF]):
530
- def __call__(self, /, path: str, recursive: bool = False) -> None: ...
531
- async def aio(self, /, path: str, recursive: bool = False) -> None: ...
1228
+ def __call__(self, /, path: str, recursive: bool = False) -> None:
1229
+ """[Alpha] Remove a file or directory in the Sandbox."""
1230
+ ...
1231
+
1232
+ async def aio(self, /, path: str, recursive: bool = False) -> None:
1233
+ """[Alpha] Remove a file or directory in the Sandbox."""
1234
+ ...
532
1235
 
533
1236
  rm: __rm_spec[typing_extensions.Self]
534
1237
 
@@ -540,7 +1243,10 @@ class Sandbox(modal.object.Object):
540
1243
  filter: typing.Optional[list[modal.file_io.FileWatchEventType]] = None,
541
1244
  recursive: typing.Optional[bool] = None,
542
1245
  timeout: typing.Optional[int] = None,
543
- ) -> typing.Iterator[modal.file_io.FileWatchEvent]: ...
1246
+ ) -> typing.Iterator[modal.file_io.FileWatchEvent]:
1247
+ """[Alpha] Watch a file or directory in the Sandbox for changes."""
1248
+ ...
1249
+
544
1250
  def aio(
545
1251
  self,
546
1252
  /,
@@ -548,18 +1254,37 @@ class Sandbox(modal.object.Object):
548
1254
  filter: typing.Optional[list[modal.file_io.FileWatchEventType]] = None,
549
1255
  recursive: typing.Optional[bool] = None,
550
1256
  timeout: typing.Optional[int] = None,
551
- ) -> typing.AsyncIterator[modal.file_io.FileWatchEvent]: ...
1257
+ ) -> typing.AsyncIterator[modal.file_io.FileWatchEvent]:
1258
+ """[Alpha] Watch a file or directory in the Sandbox for changes."""
1259
+ ...
552
1260
 
553
1261
  watch: __watch_spec[typing_extensions.Self]
554
1262
 
555
1263
  @property
556
- def stdout(self) -> modal.io_streams.StreamReader[str]: ...
1264
+ def stdout(self) -> modal.io_streams.StreamReader[str]:
1265
+ """[`StreamReader`](https://modal.com/docs/reference/modal.io_streams#modalio_streamsstreamreader) for
1266
+ the sandbox's stdout stream.
1267
+ """
1268
+ ...
1269
+
557
1270
  @property
558
- def stderr(self) -> modal.io_streams.StreamReader[str]: ...
1271
+ def stderr(self) -> modal.io_streams.StreamReader[str]:
1272
+ """[`StreamReader`](https://modal.com/docs/reference/modal.io_streams#modalio_streamsstreamreader) for
1273
+ the Sandbox's stderr stream.
1274
+ """
1275
+ ...
1276
+
559
1277
  @property
560
- def stdin(self) -> modal.io_streams.StreamWriter: ...
1278
+ def stdin(self) -> modal.io_streams.StreamWriter:
1279
+ """[`StreamWriter`](https://modal.com/docs/reference/modal.io_streams#modalio_streamsstreamwriter) for
1280
+ the Sandbox's stdin stream.
1281
+ """
1282
+ ...
1283
+
561
1284
  @property
562
- def returncode(self) -> typing.Optional[int]: ...
1285
+ def returncode(self) -> typing.Optional[int]:
1286
+ """Return code of the Sandbox process if it has finished running, else `None`."""
1287
+ ...
563
1288
 
564
1289
  class __list_spec(typing_extensions.Protocol):
565
1290
  def __call__(
@@ -569,7 +1294,12 @@ class Sandbox(modal.object.Object):
569
1294
  app_id: typing.Optional[str] = None,
570
1295
  tags: typing.Optional[dict[str, str]] = None,
571
1296
  client: typing.Optional[modal.client.Client] = None,
572
- ) -> typing.Generator[Sandbox, None, None]: ...
1297
+ ) -> typing.Generator[Sandbox, None, None]:
1298
+ """List all Sandboxes for the current Environment or App ID (if specified). If tags are specified, only
1299
+ Sandboxes that have at least those tags are returned. Returns an iterator over `Sandbox` objects.
1300
+ """
1301
+ ...
1302
+
573
1303
  def aio(
574
1304
  self,
575
1305
  /,
@@ -577,7 +1307,11 @@ class Sandbox(modal.object.Object):
577
1307
  app_id: typing.Optional[str] = None,
578
1308
  tags: typing.Optional[dict[str, str]] = None,
579
1309
  client: typing.Optional[modal.client.Client] = None,
580
- ) -> collections.abc.AsyncGenerator[Sandbox, None]: ...
1310
+ ) -> collections.abc.AsyncGenerator[Sandbox, None]:
1311
+ """List all Sandboxes for the current Environment or App ID (if specified). If tags are specified, only
1312
+ Sandboxes that have at least those tags are returned. Returns an iterator over `Sandbox` objects.
1313
+ """
1314
+ ...
581
1315
 
582
1316
  list: __list_spec
583
1317