modal 1.0.6.dev56__py3-none-any.whl → 1.0.6.dev58__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.
- modal/_functions.py +6 -8
- modal/_object.py +4 -1
- modal/_resolver.py +6 -12
- modal/_traceback.py +42 -1
- modal/_utils/async_utils.py +5 -0
- modal/client.py +32 -3
- modal/client.pyi +6 -2
- modal/cls.py +7 -7
- modal/network_file_system.py +9 -6
- modal/volume.py +14 -10
- {modal-1.0.6.dev56.dist-info → modal-1.0.6.dev58.dist-info}/METADATA +2 -2
- {modal-1.0.6.dev56.dist-info → modal-1.0.6.dev58.dist-info}/RECORD +20 -20
- modal_proto/api.proto +8 -1
- modal_proto/api_pb2.py +278 -275
- modal_proto/api_pb2.pyi +22 -4
- modal_version/__init__.py +1 -1
- {modal-1.0.6.dev56.dist-info → modal-1.0.6.dev58.dist-info}/WHEEL +0 -0
- {modal-1.0.6.dev56.dist-info → modal-1.0.6.dev58.dist-info}/entry_points.txt +0 -0
- {modal-1.0.6.dev56.dist-info → modal-1.0.6.dev58.dist-info}/licenses/LICENSE +0 -0
- {modal-1.0.6.dev56.dist-info → modal-1.0.6.dev58.dist-info}/top_level.txt +0 -0
modal/_functions.py
CHANGED
@@ -1245,14 +1245,12 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
|
|
1245
1245
|
)
|
1246
1246
|
try:
|
1247
1247
|
response = await retry_transient_errors(resolver.client.stub.FunctionGet, request)
|
1248
|
-
except
|
1249
|
-
|
1250
|
-
|
1251
|
-
|
1252
|
-
|
1253
|
-
|
1254
|
-
else:
|
1255
|
-
raise
|
1248
|
+
except NotFoundError as exc:
|
1249
|
+
# refine the error message
|
1250
|
+
env_context = f" (in the '{environment_name}' environment)" if environment_name else ""
|
1251
|
+
raise NotFoundError(
|
1252
|
+
f"Lookup failed for Function '{name}' from the '{app_name}' app{env_context}: {exc}."
|
1253
|
+
) from None
|
1256
1254
|
|
1257
1255
|
print_server_warnings(response.server_warnings)
|
1258
1256
|
|
modal/_object.py
CHANGED
@@ -8,6 +8,8 @@ from typing import Callable, ClassVar, Optional
|
|
8
8
|
from google.protobuf.message import Message
|
9
9
|
from typing_extensions import Self
|
10
10
|
|
11
|
+
from modal._traceback import suppress_tb_frames
|
12
|
+
|
11
13
|
from ._resolver import Resolver
|
12
14
|
from ._utils.async_utils import aclosing
|
13
15
|
from ._utils.deprecation import deprecation_warning
|
@@ -271,7 +273,8 @@ class _Object:
|
|
271
273
|
else:
|
272
274
|
c = client if client is not None else await _Client.from_env()
|
273
275
|
resolver = Resolver(c)
|
274
|
-
|
276
|
+
with suppress_tb_frames(1): # skip this frame by default
|
277
|
+
await resolver.load(self)
|
275
278
|
return self
|
276
279
|
|
277
280
|
|
modal/_resolver.py
CHANGED
@@ -8,13 +8,11 @@ from asyncio import Future
|
|
8
8
|
from collections.abc import Hashable
|
9
9
|
from typing import TYPE_CHECKING, Optional
|
10
10
|
|
11
|
-
from
|
12
|
-
|
11
|
+
from modal._traceback import suppress_tb_frames
|
13
12
|
from modal_proto import api_pb2
|
14
13
|
|
15
14
|
from ._utils.async_utils import TaskContext
|
16
15
|
from .client import _Client
|
17
|
-
from .exception import NotFoundError
|
18
16
|
|
19
17
|
if TYPE_CHECKING:
|
20
18
|
from rich.tree import Tree
|
@@ -144,12 +142,8 @@ class Resolver:
|
|
144
142
|
# Load the object itself
|
145
143
|
if not obj._load:
|
146
144
|
raise Exception(f"Object {obj} has no loader function")
|
147
|
-
|
148
|
-
|
149
|
-
except GRPCError as exc:
|
150
|
-
if exc.status == Status.NOT_FOUND:
|
151
|
-
raise NotFoundError(exc.message)
|
152
|
-
raise
|
145
|
+
|
146
|
+
await obj._load(obj, self, existing_object_id)
|
153
147
|
|
154
148
|
# Check that the id of functions didn't change
|
155
149
|
# Persisted refs are ignored because their life cycle is managed independently.
|
@@ -169,9 +163,9 @@ class Resolver:
|
|
169
163
|
self._local_uuid_to_future[obj.local_uuid] = cached_future
|
170
164
|
if deduplication_key is not None:
|
171
165
|
self._deduplication_cache[deduplication_key] = cached_future
|
172
|
-
|
173
|
-
|
174
|
-
|
166
|
+
with suppress_tb_frames(2):
|
167
|
+
# skip current frame + `loader()` closure frame from above
|
168
|
+
return await cached_future
|
175
169
|
|
176
170
|
def objects(self) -> list["modal._object._Object"]:
|
177
171
|
unique_objects: dict[str, "modal._object._Object"] = {}
|
modal/_traceback.py
CHANGED
@@ -8,10 +8,12 @@ so that Rich is not a dependency of the container Client.
|
|
8
8
|
import re
|
9
9
|
import sys
|
10
10
|
import traceback
|
11
|
+
import typing
|
11
12
|
import warnings
|
12
13
|
from types import TracebackType
|
13
14
|
from typing import Any, Iterable, Optional
|
14
15
|
|
16
|
+
from modal.config import config, logger
|
15
17
|
from modal_proto import api_pb2
|
16
18
|
|
17
19
|
from ._vendor.tblib import Traceback as TBLibTraceback
|
@@ -115,7 +117,7 @@ def traceback_contains_remote_call(tb: Optional[TracebackType]) -> bool:
|
|
115
117
|
def print_exception(exc: Optional[type[BaseException]], value: Optional[BaseException], tb: Optional[TracebackType]):
|
116
118
|
"""Add backwards compatibility for printing exceptions with "notes" for Python<3.11."""
|
117
119
|
traceback.print_exception(exc, value, tb)
|
118
|
-
if sys.version_info < (3, 11) and value is not None:
|
120
|
+
if sys.version_info < (3, 11) and value is not None: # type: ignore
|
119
121
|
notes = getattr(value, "__notes__", [])
|
120
122
|
print(*notes, sep="\n", file=sys.stderr)
|
121
123
|
|
@@ -127,3 +129,42 @@ def print_server_warnings(server_warnings: Iterable[api_pb2.Warning]):
|
|
127
129
|
"""
|
128
130
|
for warning in server_warnings:
|
129
131
|
warnings.warn_explicit(warning.message, ServerWarning, "<modal-server>", 0)
|
132
|
+
|
133
|
+
|
134
|
+
# for some reason, the traceback cleanup here can't be moved into a context manager :(
|
135
|
+
traceback_suppression_note = (
|
136
|
+
"Internal Modal traceback frames are suppressed for readability. Use MODAL_TRACEBACK=1 to show a full traceback."
|
137
|
+
)
|
138
|
+
|
139
|
+
|
140
|
+
class suppress_tb_frames:
|
141
|
+
def __init__(self, n: int):
|
142
|
+
self.n = n
|
143
|
+
|
144
|
+
def __enter__(self):
|
145
|
+
pass
|
146
|
+
|
147
|
+
def __exit__(
|
148
|
+
self, exc_type: Optional[type[BaseException]], exc: Optional[BaseException], tb: Optional[TracebackType]
|
149
|
+
) -> typing.Literal[False]:
|
150
|
+
# *base* exceptions like CancelledError, SystemExit etc. can come from random places,
|
151
|
+
# so we don't suppress tracebacks for those
|
152
|
+
is_base_exception = not isinstance(exc, Exception)
|
153
|
+
if config.get("traceback") or exc_type is None or is_base_exception:
|
154
|
+
return False
|
155
|
+
|
156
|
+
# modify traceback on exception object
|
157
|
+
try:
|
158
|
+
final_tb = tb
|
159
|
+
for _ in range(self.n):
|
160
|
+
final_tb = final_tb.tb_next
|
161
|
+
except AttributeError:
|
162
|
+
logger.debug(f"Failed to suppress {self.n} traceback frames from {str(exc_type)} {str(exc)}")
|
163
|
+
raise
|
164
|
+
|
165
|
+
exc.with_traceback(final_tb)
|
166
|
+
notes = getattr(exc, "__notes__", [])
|
167
|
+
if traceback_suppression_note not in notes:
|
168
|
+
# .add_note was added in Python 3.11
|
169
|
+
notes.append(traceback_suppression_note)
|
170
|
+
return False
|
modal/_utils/async_utils.py
CHANGED
@@ -4,6 +4,7 @@ import concurrent.futures
|
|
4
4
|
import functools
|
5
5
|
import inspect
|
6
6
|
import itertools
|
7
|
+
import sys
|
7
8
|
import time
|
8
9
|
import typing
|
9
10
|
from collections.abc import AsyncGenerator, AsyncIterable, Awaitable, Iterable, Iterator
|
@@ -31,6 +32,10 @@ T = TypeVar("T")
|
|
31
32
|
P = ParamSpec("P")
|
32
33
|
V = TypeVar("V")
|
33
34
|
|
35
|
+
if sys.platform == "win32":
|
36
|
+
# quick workaround for deadlocks on shutdown - need to investigate further
|
37
|
+
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
|
38
|
+
|
34
39
|
synchronizer = synchronicity.Synchronizer()
|
35
40
|
|
36
41
|
|
modal/client.py
CHANGED
@@ -18,19 +18,20 @@ from typing import (
|
|
18
18
|
import grpclib.client
|
19
19
|
from google.protobuf import empty_pb2
|
20
20
|
from google.protobuf.message import Message
|
21
|
+
from grpclib import GRPCError, Status
|
21
22
|
from synchronicity.async_wrap import asynccontextmanager
|
22
23
|
|
23
24
|
from modal._utils.async_utils import synchronizer
|
24
25
|
from modal_proto import api_grpc, api_pb2, modal_api_grpc
|
25
26
|
from modal_version import __version__
|
26
27
|
|
27
|
-
from ._traceback import print_server_warnings
|
28
|
+
from ._traceback import print_server_warnings, suppress_tb_frames
|
28
29
|
from ._utils import async_utils
|
29
30
|
from ._utils.async_utils import TaskContext, synchronize_api
|
30
31
|
from ._utils.auth_token_manager import _AuthTokenManager
|
31
32
|
from ._utils.grpc_utils import ConnectionManager, retry_transient_errors
|
32
33
|
from .config import _check_config, _is_remote, config, logger
|
33
|
-
from .exception import AuthError, ClientClosed
|
34
|
+
from .exception import AuthError, ClientClosed, NotFoundError
|
34
35
|
|
35
36
|
HEARTBEAT_INTERVAL: float = config.get("heartbeat_interval")
|
36
37
|
HEARTBEAT_TIMEOUT: float = HEARTBEAT_INTERVAL + 0.1
|
@@ -355,6 +356,33 @@ class _Client:
|
|
355
356
|
Client = synchronize_api(_Client)
|
356
357
|
|
357
358
|
|
359
|
+
class grpc_error_converter:
|
360
|
+
def __enter__(self):
|
361
|
+
pass
|
362
|
+
|
363
|
+
def __exit__(self, exc_type, exc, traceback) -> bool:
|
364
|
+
# skip all internal frames from grpclib
|
365
|
+
use_full_traceback = config.get("traceback")
|
366
|
+
with suppress_tb_frames(1):
|
367
|
+
if isinstance(exc, GRPCError):
|
368
|
+
if exc.status == Status.NOT_FOUND:
|
369
|
+
if use_full_traceback:
|
370
|
+
raise NotFoundError(exc.message)
|
371
|
+
else:
|
372
|
+
raise NotFoundError(exc.message) from None # from None to skip the grpc-internal cause
|
373
|
+
|
374
|
+
if not use_full_traceback:
|
375
|
+
# just include the frame in grpclib that actually raises the GRPCError
|
376
|
+
tb = exc.__traceback__
|
377
|
+
while tb.tb_next:
|
378
|
+
tb = tb.tb_next
|
379
|
+
exc.with_traceback(tb)
|
380
|
+
raise exc from None # from None to skip the grpc-internal cause
|
381
|
+
raise exc
|
382
|
+
|
383
|
+
return False
|
384
|
+
|
385
|
+
|
358
386
|
class UnaryUnaryWrapper(Generic[RequestType, ResponseType]):
|
359
387
|
# Calls a grpclib.UnaryUnaryMethod using a specific Client instance, respecting
|
360
388
|
# if that client is closed etc. and possibly introducing Modal-specific retry logic
|
@@ -396,7 +424,8 @@ class UnaryUnaryWrapper(Generic[RequestType, ResponseType]):
|
|
396
424
|
#
|
397
425
|
# [1]: https://github.com/vmagamedov/grpclib/blob/62f968a4c84e3f64e6966097574ff0a59969ea9b/grpclib/client.py#L844
|
398
426
|
self.wrapped_method.channel = await self.client._get_channel(self.server_url)
|
399
|
-
|
427
|
+
with suppress_tb_frames(1), grpc_error_converter():
|
428
|
+
return await self.client._call_unary(self.wrapped_method, req, timeout=timeout, metadata=metadata)
|
400
429
|
|
401
430
|
|
402
431
|
class UnaryStreamWrapper(Generic[RequestType, ResponseType]):
|
modal/client.pyi
CHANGED
@@ -33,7 +33,7 @@ class _Client:
|
|
33
33
|
server_url: str,
|
34
34
|
client_type: int,
|
35
35
|
credentials: typing.Optional[tuple[str, str]],
|
36
|
-
version: str = "1.0.6.
|
36
|
+
version: str = "1.0.6.dev58",
|
37
37
|
):
|
38
38
|
"""mdmd:hidden
|
39
39
|
The Modal client object is not intended to be instantiated directly by users.
|
@@ -163,7 +163,7 @@ class Client:
|
|
163
163
|
server_url: str,
|
164
164
|
client_type: int,
|
165
165
|
credentials: typing.Optional[tuple[str, str]],
|
166
|
-
version: str = "1.0.6.
|
166
|
+
version: str = "1.0.6.dev58",
|
167
167
|
):
|
168
168
|
"""mdmd:hidden
|
169
169
|
The Modal client object is not intended to be instantiated directly by users.
|
@@ -332,6 +332,10 @@ class Client:
|
|
332
332
|
],
|
333
333
|
) -> collections.abc.AsyncGenerator[typing.Any, None]: ...
|
334
334
|
|
335
|
+
class grpc_error_converter:
|
336
|
+
def __enter__(self): ...
|
337
|
+
def __exit__(self, exc_type, exc, traceback) -> bool: ...
|
338
|
+
|
335
339
|
class UnaryUnaryWrapper(typing.Generic[RequestType, ResponseType]):
|
336
340
|
"""Abstract base class for generic types.
|
337
341
|
|
modal/cls.py
CHANGED
@@ -642,14 +642,14 @@ More information on class parameterization can be found here: https://modal.com/
|
|
642
642
|
)
|
643
643
|
try:
|
644
644
|
response = await retry_transient_errors(resolver.client.stub.ClassGet, request)
|
645
|
+
except NotFoundError as exc:
|
646
|
+
env_context = f" (in the '{environment_name}' environment)" if environment_name else ""
|
647
|
+
raise NotFoundError(
|
648
|
+
f"Lookup failed for Cls '{name}' from the '{app_name}' app{env_context}: {exc}."
|
649
|
+
) from None
|
645
650
|
except GRPCError as exc:
|
646
|
-
if exc.status == Status.
|
647
|
-
|
648
|
-
raise NotFoundError(
|
649
|
-
f"Lookup failed for Cls '{name}' from the '{app_name}' app{env_context}: {exc.message}."
|
650
|
-
)
|
651
|
-
elif exc.status == Status.FAILED_PRECONDITION:
|
652
|
-
raise InvalidError(exc.message)
|
651
|
+
if exc.status == Status.FAILED_PRECONDITION:
|
652
|
+
raise InvalidError(exc.message) from None
|
653
653
|
else:
|
654
654
|
raise
|
655
655
|
|
modal/network_file_system.py
CHANGED
@@ -6,7 +6,6 @@ from collections.abc import AsyncIterator
|
|
6
6
|
from pathlib import Path, PurePosixPath
|
7
7
|
from typing import Any, BinaryIO, Callable, Optional, Union
|
8
8
|
|
9
|
-
from grpclib import GRPCError, Status
|
10
9
|
from synchronicity.async_wrap import asynccontextmanager
|
11
10
|
|
12
11
|
import modal
|
@@ -122,8 +121,8 @@ class _NetworkFileSystem(_Object, type_prefix="sv"):
|
|
122
121
|
try:
|
123
122
|
response = await resolver.client.stub.SharedVolumeGetOrCreate(req)
|
124
123
|
self._hydrate(response.shared_volume_id, resolver.client, None)
|
125
|
-
except
|
126
|
-
if exc.
|
124
|
+
except modal.exception.NotFoundError as exc:
|
125
|
+
if exc.args[0] == "App has wrong entity vo":
|
127
126
|
raise InvalidError(
|
128
127
|
f"Attempted to mount: `{name}` as a NetworkFileSystem " + "which already exists as a Volume"
|
129
128
|
)
|
@@ -281,8 +280,9 @@ class _NetworkFileSystem(_Object, type_prefix="sv"):
|
|
281
280
|
req = api_pb2.SharedVolumeGetFileRequest(shared_volume_id=self.object_id, path=path)
|
282
281
|
try:
|
283
282
|
response = await retry_transient_errors(self._client.stub.SharedVolumeGetFile, req)
|
284
|
-
except
|
285
|
-
raise FileNotFoundError(exc.
|
283
|
+
except modal.exception.NotFoundError as exc:
|
284
|
+
raise FileNotFoundError(exc.args[0])
|
285
|
+
|
286
286
|
if response.WhichOneof("data_oneof") == "data":
|
287
287
|
yield response.data
|
288
288
|
else:
|
@@ -363,7 +363,10 @@ class _NetworkFileSystem(_Object, type_prefix="sv"):
|
|
363
363
|
async def remove_file(self, path: str, recursive=False):
|
364
364
|
"""Remove a file in a network file system."""
|
365
365
|
req = api_pb2.SharedVolumeRemoveFileRequest(shared_volume_id=self.object_id, path=path, recursive=recursive)
|
366
|
-
|
366
|
+
try:
|
367
|
+
await retry_transient_errors(self._client.stub.SharedVolumeRemoveFile, req)
|
368
|
+
except modal.exception.NotFoundError as exc:
|
369
|
+
raise FileNotFoundError(exc.args[0])
|
367
370
|
|
368
371
|
|
369
372
|
NetworkFileSystem = synchronize_api(_NetworkFileSystem)
|
modal/volume.py
CHANGED
@@ -26,6 +26,7 @@ from google.protobuf.message import Message
|
|
26
26
|
from grpclib import GRPCError, Status
|
27
27
|
from synchronicity.async_wrap import asynccontextmanager
|
28
28
|
|
29
|
+
import modal.exception
|
29
30
|
import modal_proto.api_pb2
|
30
31
|
from modal.exception import InvalidError, VolumeUploadTimeoutError
|
31
32
|
from modal_proto import api_pb2
|
@@ -449,8 +450,8 @@ class _Volume(_Object, type_prefix="vo"):
|
|
449
450
|
|
450
451
|
try:
|
451
452
|
response = await retry_transient_errors(self._client.stub.VolumeGetFile2, req)
|
452
|
-
except
|
453
|
-
raise FileNotFoundError(exc.
|
453
|
+
except modal.exception.NotFoundError as exc:
|
454
|
+
raise FileNotFoundError(exc.args[0])
|
454
455
|
|
455
456
|
async def read_block(block_url: str) -> bytes:
|
456
457
|
async with ClientSessionRegistry.get_session().get(block_url) as get_response:
|
@@ -483,8 +484,8 @@ class _Volume(_Object, type_prefix="vo"):
|
|
483
484
|
|
484
485
|
try:
|
485
486
|
response = await retry_transient_errors(self._client.stub.VolumeGetFile2, req)
|
486
|
-
except
|
487
|
-
raise FileNotFoundError(exc.
|
487
|
+
except modal.exception.NotFoundError as exc:
|
488
|
+
raise FileNotFoundError(exc.args[0])
|
488
489
|
|
489
490
|
# TODO(dflemstr): Sane default limit? Make configurable?
|
490
491
|
download_semaphore = asyncio.Semaphore(multiprocessing.cpu_count())
|
@@ -526,12 +527,15 @@ class _Volume(_Object, type_prefix="vo"):
|
|
526
527
|
if self._read_only:
|
527
528
|
raise InvalidError("Read-only Volume can not be written to")
|
528
529
|
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
530
|
+
try:
|
531
|
+
if self._is_v1:
|
532
|
+
req = api_pb2.VolumeRemoveFileRequest(volume_id=self.object_id, path=path, recursive=recursive)
|
533
|
+
await retry_transient_errors(self._client.stub.VolumeRemoveFile, req)
|
534
|
+
else:
|
535
|
+
req = api_pb2.VolumeRemoveFile2Request(volume_id=self.object_id, path=path, recursive=recursive)
|
536
|
+
await retry_transient_errors(self._client.stub.VolumeRemoveFile2, req)
|
537
|
+
except modal.exception.NotFoundError as exc:
|
538
|
+
raise FileNotFoundError(exc.args[0])
|
535
539
|
|
536
540
|
@live_method
|
537
541
|
async def copy_files(self, src_paths: Sequence[str], dst_path: str, recursive: bool = False) -> None:
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: modal
|
3
|
-
Version: 1.0.6.
|
3
|
+
Version: 1.0.6.dev58
|
4
4
|
Summary: Python client library for Modal
|
5
5
|
Author-email: Modal Labs <support@modal.com>
|
6
6
|
License: Apache-2.0
|
@@ -22,7 +22,7 @@ Requires-Dist: click~=8.1.0
|
|
22
22
|
Requires-Dist: grpclib<0.4.9,>=0.4.7
|
23
23
|
Requires-Dist: protobuf!=4.24.0,<7.0,>=3.19
|
24
24
|
Requires-Dist: rich>=12.0.0
|
25
|
-
Requires-Dist: synchronicity~=0.
|
25
|
+
Requires-Dist: synchronicity~=0.10.1
|
26
26
|
Requires-Dist: toml
|
27
27
|
Requires-Dist: typer>=0.9
|
28
28
|
Requires-Dist: types-certifi
|
@@ -3,17 +3,17 @@ modal/__main__.py,sha256=sTJcc9EbDuCKSwg3tL6ZckFw9WWdlkXW8mId1IvJCNc,2846
|
|
3
3
|
modal/_clustered_functions.py,sha256=kTf-9YBXY88NutC1akI-gCbvf01RhMPCw-zoOI_YIUE,2700
|
4
4
|
modal/_clustered_functions.pyi,sha256=_QKM87tdYwcALSGth8a0-9qXl02fZK6zMfEGEoYz7eA,1007
|
5
5
|
modal/_container_entrypoint.py,sha256=1qBMNY_E9ICC_sRCtillMxmKPsmxJl1J0_qOAG8rH-0,28288
|
6
|
-
modal/_functions.py,sha256=
|
6
|
+
modal/_functions.py,sha256=zjtdBd41AzxshemfMrohAlfsMlyhPorjeyNde9gwF0k,81169
|
7
7
|
modal/_ipython.py,sha256=TW1fkVOmZL3YYqdS2YlM1hqpf654Yf8ZyybHdBnlhSw,301
|
8
8
|
modal/_location.py,sha256=joiX-0ZeutEUDTrrqLF1GHXCdVLF-rHzstocbMcd_-k,366
|
9
|
-
modal/_object.py,sha256=
|
9
|
+
modal/_object.py,sha256=vzRWhAcFJDM8ZmiUSDgSj9gJhLZJA-wjLVvTl984N4A,11295
|
10
10
|
modal/_output.py,sha256=LRM9KroHuR7t5pq8iLYjpFz1sQrHYan2kvRDjT6KAw4,26082
|
11
11
|
modal/_partial_function.py,sha256=B1J4S9W-La0NHaVmY1aCuH0E3QxJHIX6ZWY5eNTQ7io,37142
|
12
12
|
modal/_pty.py,sha256=JZfPDDpzqICZqtyPI_oMJf_9w-p_lLNuzHhwhodUXio,1329
|
13
|
-
modal/_resolver.py,sha256
|
13
|
+
modal/_resolver.py,sha256=2RWvm34cNSnbv1v7izJMNZgfvpLDD6LzaBlr0lIrLnY,7364
|
14
14
|
modal/_resources.py,sha256=NMAp0GCLutiZI4GuKSIVnRHVlstoD3hNGUabjTUtzf4,1794
|
15
15
|
modal/_serialization.py,sha256=wt09fOwo-E9ATlOG91O9RXCTPRNtsm97v4Unk8Bzd-8,24145
|
16
|
-
modal/_traceback.py,sha256=
|
16
|
+
modal/_traceback.py,sha256=muKP7RbAXq74UGwkaVIdOxDdfDug0UcDKr9fe4LL3m8,6503
|
17
17
|
modal/_tunnel.py,sha256=zTBxBiuH1O22tS1OliAJdIsSmaZS8PlnifS_6S5z-mk,6320
|
18
18
|
modal/_tunnel.pyi,sha256=rvC7USR2BcKkbZIeCJXwf7-UfGE-LPLjKsGNiK7Lxa4,13366
|
19
19
|
modal/_type_manager.py,sha256=DWjgmjYJuOagw2erin506UUbG2H5UzZCFEekS-7hmfA,9087
|
@@ -21,11 +21,11 @@ modal/_watcher.py,sha256=K6LYnlmSGQB4tWWI9JADv-tvSvQ1j522FwT71B51CX8,3584
|
|
21
21
|
modal/app.py,sha256=cCgX6rYbEB__q2XoAF2OAeH--L0EM4XWZ820YWglKSQ,48134
|
22
22
|
modal/app.pyi,sha256=cXiSTu2bwu6csAUdkOlh7mr9tPvtaS2qWSEhlC1UxAg,43787
|
23
23
|
modal/call_graph.py,sha256=1g2DGcMIJvRy-xKicuf63IVE98gJSnQsr8R_NVMptNc,2581
|
24
|
-
modal/client.py,sha256=
|
25
|
-
modal/client.pyi,sha256=
|
24
|
+
modal/client.py,sha256=pBSZ7lv5dezIL9U9H4tpE0Yz6qA1n0NoNbnJ3KCQMMA,18252
|
25
|
+
modal/client.pyi,sha256=ygXM4KBT7Yy2XdLtVgFGeu_BXF5GrTSnR6EPR6rkhU4,15390
|
26
26
|
modal/cloud_bucket_mount.py,sha256=YOe9nnvSr4ZbeCn587d7_VhE9IioZYRvF9VYQTQux08,5914
|
27
27
|
modal/cloud_bucket_mount.pyi,sha256=-qSfYAQvIoO_l2wsCCGTG5ZUwQieNKXdAO00yP1-LYU,7394
|
28
|
-
modal/cls.py,sha256=
|
28
|
+
modal/cls.py,sha256=7A0xGnugQzm8dOfnKMjLjtqekRlRtQ0jPFRYgq6xdUM,40018
|
29
29
|
modal/cls.pyi,sha256=_tZ5qrlL-ZDEcD-mf9BZkkNH5XPr4SmGTEQ-RVmqF3I,27772
|
30
30
|
modal/config.py,sha256=FqVewLPVVR4feq_46JBENiCzqTuXKpnvQZxaeWbS39g,12009
|
31
31
|
modal/container_process.py,sha256=1m4NPg0lgZmlG9OTkhHbjafqlqoo4lLv-A-X5lV21yo,6852
|
@@ -47,7 +47,7 @@ modal/io_streams.py,sha256=ut9tY_yEtiBsgQ40u_72Ns87IZHfbMxfnh8t6U9RSGA,16204
|
|
47
47
|
modal/io_streams.pyi,sha256=aOun_jUFKHSJyUY6-7gKvNoxzcULsa8_hxdtEO7v-gk,13980
|
48
48
|
modal/mount.py,sha256=q-pPeVxAmte-G_LDpbFwaNs2Rb2MIpscfnCXzkhxrOI,36734
|
49
49
|
modal/mount.pyi,sha256=n6AuS8J3bTCQj750nVZZdVBvzCAlSM2fyxAt_5LLFik,20264
|
50
|
-
modal/network_file_system.py,sha256=
|
50
|
+
modal/network_file_system.py,sha256=AdjxI_hCYaDZz60gOuJeig8yourfWhHmEpn13C_fnMA,14775
|
51
51
|
modal/network_file_system.pyi,sha256=Td_IobHr84iLo_9LZKQ4tNdUB60yjX8QWBaFiUvhfi8,17685
|
52
52
|
modal/object.py,sha256=bTeskuY8JFrESjU4_UL_nTwYlBQdOLmVaOX3X6EMxsg,164
|
53
53
|
modal/object.pyi,sha256=751TV6BntarPsErf0HDQPsvePjWFf0JZK8ZAiRpM1yg,6627
|
@@ -78,7 +78,7 @@ modal/snapshot.pyi,sha256=0q83hlmWxAhDu8xwZyL5VmYh0i8Tigf7S60or2k30L8,1682
|
|
78
78
|
modal/stream_type.py,sha256=A6320qoAAWhEfwOCZfGtymQTu5AfLfJXXgARqooTPvY,417
|
79
79
|
modal/token_flow.py,sha256=0_4KabXKsuE4OXTJ1OuLOtA-b1sesShztMZkkRFK7tA,7605
|
80
80
|
modal/token_flow.pyi,sha256=eirYjyqbRiT3GCKMIPHJPpkvBTu8WxDKqSHehWaJI_4,2533
|
81
|
-
modal/volume.py,sha256=
|
81
|
+
modal/volume.py,sha256=4AcgWhqq-zgSbmX-Tx7u2oo1gPLW5mxfb_oZfVSzpQs,44449
|
82
82
|
modal/volume.pyi,sha256=sjr67f0npiRzl2j3blrcMA_QSoogJAS0xLqWI06xWXQ,40727
|
83
83
|
modal/_runtime/__init__.py,sha256=MIEP8jhXUeGq_eCjYFcqN5b1bxBM4fdk0VESpjWR0fc,28
|
84
84
|
modal/_runtime/asgi.py,sha256=_2xSTsDD27Cit7xnMs4lzkJA2wzer2_N4Oa3BkXFzVA,22521
|
@@ -91,7 +91,7 @@ modal/_runtime/telemetry.py,sha256=T1RoAGyjBDr1swiM6pPsGRSITm7LI5FDK18oNXxY08U,5
|
|
91
91
|
modal/_runtime/user_code_imports.py,sha256=78wJyleqY2RVibqcpbDQyfWVBVT9BjyHPeoV9WdwV5Y,17720
|
92
92
|
modal/_utils/__init__.py,sha256=waLjl5c6IPDhSsdWAm9Bji4e2PVxamYABKAze6CHVXY,28
|
93
93
|
modal/_utils/app_utils.py,sha256=88BT4TPLWfYAQwKTHcyzNQRHg8n9B-QE2UyJs96iV-0,108
|
94
|
-
modal/_utils/async_utils.py,sha256=
|
94
|
+
modal/_utils/async_utils.py,sha256=ot8NiPGZ5bRJhY5ilZyjNgx24VI-1BIpCu054oLHDf0,29556
|
95
95
|
modal/_utils/auth_token_manager.py,sha256=4YS0pBfwbuNFy5DoAIOnBNCcYjS9rNCMv4zSVGybiOw,5245
|
96
96
|
modal/_utils/blob_utils.py,sha256=v2NAQVVGx1AQjHQ7-2T64x5rYtwjFFykxDXb-0grrzA,21022
|
97
97
|
modal/_utils/bytes_io_segment_payload.py,sha256=vaXPq8b52-x6G2hwE7SrjS58pg_aRm7gV3bn3yjmTzQ,4261
|
@@ -151,7 +151,7 @@ modal/requirements/2025.06.txt,sha256=KxDaVTOwatHvboDo4lorlgJ7-n-MfAwbPwxJ0zcJqr
|
|
151
151
|
modal/requirements/PREVIEW.txt,sha256=KxDaVTOwatHvboDo4lorlgJ7-n-MfAwbPwxJ0zcJqrs,312
|
152
152
|
modal/requirements/README.md,sha256=9tK76KP0Uph7O0M5oUgsSwEZDj5y-dcUPsnpR0Sc-Ik,854
|
153
153
|
modal/requirements/base-images.json,sha256=JYSDAgHTl-WrV_TZW5icY-IJEnbe2eQ4CZ_KN6EOZKU,1304
|
154
|
-
modal-1.0.6.
|
154
|
+
modal-1.0.6.dev58.dist-info/licenses/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
|
155
155
|
modal_docs/__init__.py,sha256=svYKtV8HDwDCN86zbdWqyq5T8sMdGDj0PVlzc2tIxDM,28
|
156
156
|
modal_docs/gen_cli_docs.py,sha256=c1yfBS_x--gL5bs0N4ihMwqwX8l3IBWSkBAKNNIi6bQ,3801
|
157
157
|
modal_docs/gen_reference_docs.py,sha256=d_CQUGQ0rfw28u75I2mov9AlS773z9rG40-yq5o7g2U,6359
|
@@ -159,10 +159,10 @@ modal_docs/mdmd/__init__.py,sha256=svYKtV8HDwDCN86zbdWqyq5T8sMdGDj0PVlzc2tIxDM,2
|
|
159
159
|
modal_docs/mdmd/mdmd.py,sha256=eW5MzrEl7mSclDo4Uv64sQ1-4IyLggldbgUJdBVLDdI,6449
|
160
160
|
modal_docs/mdmd/signatures.py,sha256=XJaZrK7Mdepk5fdX51A8uENiLFNil85Ud0d4MH8H5f0,3218
|
161
161
|
modal_proto/__init__.py,sha256=MIEP8jhXUeGq_eCjYFcqN5b1bxBM4fdk0VESpjWR0fc,28
|
162
|
-
modal_proto/api.proto,sha256=
|
162
|
+
modal_proto/api.proto,sha256=idhfshJXfQ79fmRsGdJuBu9m6Q7UDOSHKAxJlvqR20g,99923
|
163
163
|
modal_proto/api_grpc.py,sha256=F7Hu-1Yg7p5a2SbKw9yR4AgpyU0ntvgZTaVbIJMR0DE,122366
|
164
|
-
modal_proto/api_pb2.py,sha256=
|
165
|
-
modal_proto/api_pb2.pyi,sha256=
|
164
|
+
modal_proto/api_pb2.py,sha256=l8mSgayid4o2z62KDprp3XsoDS7HNydohaUJKh7xoSo,350428
|
165
|
+
modal_proto/api_pb2.pyi,sha256=JTACUgjpwAqk8I2982mXEG3Y_8DfKim5LP9WGayqlAg,478686
|
166
166
|
modal_proto/api_pb2_grpc.py,sha256=pIFrNmCOgRRcIW8A1Ekja9Po6fHcsj54ExDZFzTpYe4,264347
|
167
167
|
modal_proto/api_pb2_grpc.pyi,sha256=vtxrQ9xnQG6ZRXjp2uk43Mb7wV7F4qGYuVl5JUBc8jI,61968
|
168
168
|
modal_proto/modal_api_grpc.py,sha256=Yl_fGbSIuX2FAEnURkYpKqshs7kbNqtz5HlTJEXkbhE,18487
|
@@ -174,10 +174,10 @@ modal_proto/options_pb2.pyi,sha256=l7DBrbLO7q3Ir-XDkWsajm0d0TQqqrfuX54i4BMpdQg,1
|
|
174
174
|
modal_proto/options_pb2_grpc.py,sha256=1oboBPFxaTEXt9Aw7EAj8gXHDCNMhZD2VXqocC9l_gk,159
|
175
175
|
modal_proto/options_pb2_grpc.pyi,sha256=CImmhxHsYnF09iENPoe8S4J-n93jtgUYD2JPAc0yJSI,247
|
176
176
|
modal_proto/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
177
|
-
modal_version/__init__.py,sha256=
|
177
|
+
modal_version/__init__.py,sha256=1einvN_8VxP76z0bSJw0M0Lbdk_rkOSvd3BS6nLLqYk,121
|
178
178
|
modal_version/__main__.py,sha256=2FO0yYQQwDTh6udt1h-cBnGd1c4ZyHnHSI4BksxzVac,105
|
179
|
-
modal-1.0.6.
|
180
|
-
modal-1.0.6.
|
181
|
-
modal-1.0.6.
|
182
|
-
modal-1.0.6.
|
183
|
-
modal-1.0.6.
|
179
|
+
modal-1.0.6.dev58.dist-info/METADATA,sha256=zPncMGPavdAh9cj9D8eRvTRpU1qD7lnbo2YDrEzc2Bw,2462
|
180
|
+
modal-1.0.6.dev58.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
|
181
|
+
modal-1.0.6.dev58.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
|
182
|
+
modal-1.0.6.dev58.dist-info/top_level.txt,sha256=4BWzoKYREKUZ5iyPzZpjqx4G8uB5TWxXPDwibLcVa7k,43
|
183
|
+
modal-1.0.6.dev58.dist-info/RECORD,,
|
modal_proto/api.proto
CHANGED
@@ -2609,8 +2609,15 @@ message SandboxListResponse {
|
|
2609
2609
|
}
|
2610
2610
|
|
2611
2611
|
message SandboxRestoreRequest {
|
2612
|
+
enum SandboxNameOverrideType {
|
2613
|
+
SANDBOX_NAME_OVERRIDE_TYPE_UNSPECIFIED = 0;
|
2614
|
+
SANDBOX_NAME_OVERRIDE_TYPE_NONE = 1;
|
2615
|
+
SANDBOX_NAME_OVERRIDE_TYPE_STRING = 2;
|
2616
|
+
}
|
2617
|
+
|
2612
2618
|
string snapshot_id = 1;
|
2613
|
-
string
|
2619
|
+
string sandbox_name_override = 2;
|
2620
|
+
SandboxNameOverrideType sandbox_name_override_type = 3;
|
2614
2621
|
}
|
2615
2622
|
|
2616
2623
|
message SandboxRestoreResponse {
|