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.
- modal/__init__.py +0 -2
- modal/__main__.py +3 -4
- modal/_billing.py +80 -0
- modal/_clustered_functions.py +7 -3
- modal/_clustered_functions.pyi +15 -3
- modal/_container_entrypoint.py +51 -69
- modal/_functions.py +508 -240
- modal/_grpc_client.py +171 -0
- modal/_load_context.py +105 -0
- modal/_object.py +81 -21
- modal/_output.py +58 -45
- modal/_partial_function.py +48 -73
- modal/_pty.py +7 -3
- modal/_resolver.py +26 -46
- modal/_runtime/asgi.py +4 -3
- modal/_runtime/container_io_manager.py +358 -220
- modal/_runtime/container_io_manager.pyi +296 -101
- modal/_runtime/execution_context.py +18 -2
- modal/_runtime/execution_context.pyi +64 -7
- modal/_runtime/gpu_memory_snapshot.py +262 -57
- modal/_runtime/user_code_imports.py +28 -58
- modal/_serialization.py +90 -6
- modal/_traceback.py +42 -1
- modal/_tunnel.pyi +380 -12
- modal/_utils/async_utils.py +84 -29
- modal/_utils/auth_token_manager.py +111 -0
- modal/_utils/blob_utils.py +181 -58
- modal/_utils/deprecation.py +19 -0
- modal/_utils/function_utils.py +91 -47
- modal/_utils/grpc_utils.py +89 -66
- modal/_utils/mount_utils.py +26 -1
- modal/_utils/name_utils.py +17 -3
- modal/_utils/task_command_router_client.py +536 -0
- modal/_utils/time_utils.py +34 -6
- modal/app.py +256 -88
- modal/app.pyi +909 -92
- modal/billing.py +5 -0
- modal/builder/2025.06.txt +18 -0
- modal/builder/PREVIEW.txt +18 -0
- modal/builder/base-images.json +58 -0
- modal/cli/_download.py +19 -3
- modal/cli/_traceback.py +3 -2
- modal/cli/app.py +4 -4
- modal/cli/cluster.py +15 -7
- modal/cli/config.py +5 -3
- modal/cli/container.py +7 -6
- modal/cli/dict.py +22 -16
- modal/cli/entry_point.py +12 -5
- modal/cli/environment.py +5 -4
- modal/cli/import_refs.py +3 -3
- modal/cli/launch.py +102 -5
- modal/cli/network_file_system.py +11 -12
- modal/cli/profile.py +3 -2
- modal/cli/programs/launch_instance_ssh.py +94 -0
- modal/cli/programs/run_jupyter.py +1 -1
- modal/cli/programs/run_marimo.py +95 -0
- modal/cli/programs/vscode.py +1 -1
- modal/cli/queues.py +57 -26
- modal/cli/run.py +91 -23
- modal/cli/secret.py +48 -22
- modal/cli/token.py +7 -8
- modal/cli/utils.py +4 -7
- modal/cli/volume.py +31 -25
- modal/client.py +15 -85
- modal/client.pyi +183 -62
- modal/cloud_bucket_mount.py +5 -3
- modal/cloud_bucket_mount.pyi +197 -5
- modal/cls.py +200 -126
- modal/cls.pyi +446 -68
- modal/config.py +29 -11
- modal/container_process.py +319 -19
- modal/container_process.pyi +190 -20
- modal/dict.py +290 -71
- modal/dict.pyi +835 -83
- modal/environments.py +15 -27
- modal/environments.pyi +46 -24
- modal/exception.py +14 -2
- modal/experimental/__init__.py +194 -40
- modal/experimental/flash.py +618 -0
- modal/experimental/flash.pyi +380 -0
- modal/experimental/ipython.py +11 -7
- modal/file_io.py +29 -36
- modal/file_io.pyi +251 -53
- modal/file_pattern_matcher.py +56 -16
- modal/functions.pyi +673 -92
- modal/gpu.py +1 -1
- modal/image.py +528 -176
- modal/image.pyi +1572 -145
- modal/io_streams.py +458 -128
- modal/io_streams.pyi +433 -52
- modal/mount.py +216 -151
- modal/mount.pyi +225 -78
- modal/network_file_system.py +45 -62
- modal/network_file_system.pyi +277 -56
- modal/object.pyi +93 -17
- modal/parallel_map.py +942 -129
- modal/parallel_map.pyi +294 -15
- modal/partial_function.py +0 -2
- modal/partial_function.pyi +234 -19
- modal/proxy.py +17 -8
- modal/proxy.pyi +36 -3
- modal/queue.py +270 -65
- modal/queue.pyi +817 -57
- modal/runner.py +115 -101
- modal/runner.pyi +205 -49
- modal/sandbox.py +512 -136
- modal/sandbox.pyi +845 -111
- modal/schedule.py +1 -1
- modal/secret.py +300 -70
- modal/secret.pyi +589 -34
- modal/serving.py +7 -11
- modal/serving.pyi +7 -8
- modal/snapshot.py +11 -8
- modal/snapshot.pyi +25 -4
- modal/token_flow.py +4 -4
- modal/token_flow.pyi +28 -8
- modal/volume.py +416 -158
- modal/volume.pyi +1117 -121
- {modal-1.0.3.dev10.dist-info → modal-1.2.3.dev7.dist-info}/METADATA +10 -9
- modal-1.2.3.dev7.dist-info/RECORD +195 -0
- modal_docs/mdmd/mdmd.py +17 -4
- modal_proto/api.proto +534 -79
- modal_proto/api_grpc.py +337 -1
- modal_proto/api_pb2.py +1522 -968
- modal_proto/api_pb2.pyi +1619 -134
- modal_proto/api_pb2_grpc.py +699 -4
- modal_proto/api_pb2_grpc.pyi +226 -14
- modal_proto/modal_api_grpc.py +175 -154
- modal_proto/sandbox_router.proto +145 -0
- modal_proto/sandbox_router_grpc.py +105 -0
- modal_proto/sandbox_router_pb2.py +149 -0
- modal_proto/sandbox_router_pb2.pyi +333 -0
- modal_proto/sandbox_router_pb2_grpc.py +203 -0
- modal_proto/sandbox_router_pb2_grpc.pyi +75 -0
- modal_proto/task_command_router.proto +144 -0
- modal_proto/task_command_router_grpc.py +105 -0
- modal_proto/task_command_router_pb2.py +149 -0
- modal_proto/task_command_router_pb2.pyi +333 -0
- modal_proto/task_command_router_pb2_grpc.py +203 -0
- modal_proto/task_command_router_pb2_grpc.pyi +75 -0
- modal_version/__init__.py +1 -1
- modal/requirements/PREVIEW.txt +0 -16
- modal/requirements/base-images.json +0 -26
- modal-1.0.3.dev10.dist-info/RECORD +0 -179
- modal_proto/modal_options_grpc.py +0 -3
- modal_proto/options.proto +0 -19
- modal_proto/options_grpc.py +0 -3
- modal_proto/options_pb2.py +0 -35
- modal_proto/options_pb2.pyi +0 -20
- modal_proto/options_pb2_grpc.py +0 -4
- modal_proto/options_pb2_grpc.pyi +0 -7
- /modal/{requirements → builder}/2023.12.312.txt +0 -0
- /modal/{requirements → builder}/2023.12.txt +0 -0
- /modal/{requirements → builder}/2024.04.txt +0 -0
- /modal/{requirements → builder}/2024.10.txt +0 -0
- /modal/{requirements → builder}/README.md +0 -0
- {modal-1.0.3.dev10.dist-info → modal-1.2.3.dev7.dist-info}/WHEEL +0 -0
- {modal-1.0.3.dev10.dist-info → modal-1.2.3.dev7.dist-info}/entry_points.txt +0 -0
- {modal-1.0.3.dev10.dist-info → modal-1.2.3.dev7.dist-info}/licenses/LICENSE +0 -0
- {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(
|
|
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
|
-
|
|
92
|
+
args: collections.abc.Sequence[str],
|
|
42
93
|
image: modal.image._Image,
|
|
43
|
-
secrets: collections.abc.
|
|
44
|
-
|
|
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
|
-
|
|
121
|
+
verbose: bool = False,
|
|
122
|
+
) -> _Sandbox:
|
|
123
|
+
"""mdmd:hidden"""
|
|
124
|
+
...
|
|
125
|
+
|
|
66
126
|
@staticmethod
|
|
67
127
|
async def create(
|
|
68
|
-
*
|
|
128
|
+
*args: str,
|
|
69
129
|
app: typing.Optional[modal.app._App] = None,
|
|
70
|
-
|
|
130
|
+
name: typing.Optional[str] = None,
|
|
71
131
|
image: typing.Optional[modal.image._Image] = None,
|
|
72
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
*
|
|
179
|
+
*args: str,
|
|
98
180
|
app: typing.Optional[modal.app._App] = None,
|
|
99
|
-
|
|
181
|
+
name: typing.Optional[str] = None,
|
|
100
182
|
image: typing.Optional[modal.image._Image] = None,
|
|
101
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
174
|
-
|
|
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
|
-
|
|
492
|
+
@staticmethod
|
|
493
|
+
def _default_pty_info() -> modal_proto.api_pb2.PTYInfo: ...
|
|
210
494
|
@staticmethod
|
|
211
495
|
def _new(
|
|
212
|
-
|
|
496
|
+
args: collections.abc.Sequence[str],
|
|
213
497
|
image: modal.image.Image,
|
|
214
|
-
secrets: collections.abc.
|
|
215
|
-
|
|
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
|
-
|
|
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
|
-
*
|
|
533
|
+
*args: str,
|
|
242
534
|
app: typing.Optional[modal.app.App] = None,
|
|
243
|
-
|
|
535
|
+
name: typing.Optional[str] = None,
|
|
244
536
|
image: typing.Optional[modal.image.Image] = None,
|
|
245
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
*
|
|
587
|
+
*args: str,
|
|
274
588
|
app: typing.Optional[modal.app.App] = None,
|
|
275
|
-
|
|
589
|
+
name: typing.Optional[str] = None,
|
|
276
590
|
image: typing.Optional[modal.image.Image] = None,
|
|
277
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
*
|
|
644
|
+
*args: str,
|
|
310
645
|
app: typing.Optional[modal.app.App] = None,
|
|
311
|
-
|
|
646
|
+
name: typing.Optional[str] = None,
|
|
312
647
|
image: typing.Optional[modal.image.Image] = None,
|
|
313
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
-
*
|
|
691
|
+
*args: str,
|
|
343
692
|
app: typing.Optional[modal.app.App] = None,
|
|
344
|
-
|
|
693
|
+
name: typing.Optional[str] = None,
|
|
345
694
|
image: typing.Optional[modal.image.Image] = None,
|
|
346
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
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,
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|