modal 0.67.16__py3-none-any.whl → 0.67.18__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/_utils/blob_utils.py +18 -4
- modal/client.pyi +2 -2
- {modal-0.67.16.dist-info → modal-0.67.18.dist-info}/METADATA +1 -1
- {modal-0.67.16.dist-info → modal-0.67.18.dist-info}/RECORD +16 -16
- modal_proto/api.proto +13 -0
- modal_proto/api_grpc.py +16 -0
- modal_proto/api_pb2.py +241 -221
- modal_proto/api_pb2.pyi +41 -0
- modal_proto/api_pb2_grpc.py +33 -0
- modal_proto/api_pb2_grpc.pyi +10 -0
- modal_proto/modal_api_grpc.py +1 -0
- modal_version/_version_generated.py +1 -1
- {modal-0.67.16.dist-info → modal-0.67.18.dist-info}/LICENSE +0 -0
- {modal-0.67.16.dist-info → modal-0.67.18.dist-info}/WHEEL +0 -0
- {modal-0.67.16.dist-info → modal-0.67.18.dist-info}/entry_points.txt +0 -0
- {modal-0.67.16.dist-info → modal-0.67.18.dist-info}/top_level.txt +0 -0
modal/_utils/blob_utils.py
CHANGED
@@ -5,6 +5,7 @@ import hashlib
|
|
5
5
|
import io
|
6
6
|
import os
|
7
7
|
import platform
|
8
|
+
import time
|
8
9
|
from collections.abc import AsyncIterator
|
9
10
|
from contextlib import AbstractContextManager, contextmanager
|
10
11
|
from pathlib import Path, PurePosixPath
|
@@ -289,11 +290,18 @@ async def _blob_upload(
|
|
289
290
|
|
290
291
|
|
291
292
|
async def blob_upload(payload: bytes, stub: ModalClientModal) -> str:
|
293
|
+
size_mib = len(payload) / 1024 / 1024
|
294
|
+
logger.debug(f"Uploading large blob of size {size_mib:.2f} MiB")
|
295
|
+
t0 = time.time()
|
292
296
|
if isinstance(payload, str):
|
293
297
|
logger.warning("Blob uploading string, not bytes - auto-encoding as utf8")
|
294
298
|
payload = payload.encode("utf8")
|
295
299
|
upload_hashes = get_upload_hashes(payload)
|
296
|
-
|
300
|
+
blob_id = await _blob_upload(upload_hashes, payload, stub)
|
301
|
+
dur_s = max(time.time() - t0, 0.001) # avoid division by zero
|
302
|
+
throughput_mib_s = (size_mib) / dur_s
|
303
|
+
logger.debug(f"Uploaded large blob of size {size_mib:.2f} MiB ({throughput_mib_s:.2f} MiB/s)." f" {blob_id}")
|
304
|
+
return blob_id
|
297
305
|
|
298
306
|
|
299
307
|
async def blob_upload_file(
|
@@ -318,11 +326,17 @@ async def _download_from_url(download_url: str) -> bytes:
|
|
318
326
|
|
319
327
|
|
320
328
|
async def blob_download(blob_id: str, stub: ModalClientModal) -> bytes:
|
321
|
-
|
329
|
+
"""Convenience function for reading all of the downloaded file into memory."""
|
330
|
+
logger.debug(f"Downloading large blob {blob_id}")
|
331
|
+
t0 = time.time()
|
322
332
|
req = api_pb2.BlobGetRequest(blob_id=blob_id)
|
323
333
|
resp = await retry_transient_errors(stub.BlobGet, req)
|
324
|
-
|
325
|
-
|
334
|
+
data = await _download_from_url(resp.download_url)
|
335
|
+
size_mib = len(data) / 1024 / 1024
|
336
|
+
dur_s = max(time.time() - t0, 0.001) # avoid division by zero
|
337
|
+
throughput_mib_s = size_mib / dur_s
|
338
|
+
logger.debug(f"Downloaded large blob {blob_id} of size {size_mib:.2f} MiB ({throughput_mib_s:.2f} MiB/s)")
|
339
|
+
return data
|
326
340
|
|
327
341
|
|
328
342
|
async def blob_iter(blob_id: str, stub: ModalClientModal) -> AsyncIterator[bytes]:
|
modal/client.pyi
CHANGED
@@ -26,7 +26,7 @@ class _Client:
|
|
26
26
|
_stub: typing.Optional[modal_proto.api_grpc.ModalClientStub]
|
27
27
|
|
28
28
|
def __init__(
|
29
|
-
self, server_url: str, client_type: int, credentials: typing.Optional[tuple[str, str]], version: str = "0.67.
|
29
|
+
self, server_url: str, client_type: int, credentials: typing.Optional[tuple[str, str]], version: str = "0.67.18"
|
30
30
|
): ...
|
31
31
|
def is_closed(self) -> bool: ...
|
32
32
|
@property
|
@@ -81,7 +81,7 @@ class Client:
|
|
81
81
|
_stub: typing.Optional[modal_proto.api_grpc.ModalClientStub]
|
82
82
|
|
83
83
|
def __init__(
|
84
|
-
self, server_url: str, client_type: int, credentials: typing.Optional[tuple[str, str]], version: str = "0.67.
|
84
|
+
self, server_url: str, client_type: int, credentials: typing.Optional[tuple[str, str]], version: str = "0.67.18"
|
85
85
|
): ...
|
86
86
|
def is_closed(self) -> bool: ...
|
87
87
|
@property
|
@@ -19,7 +19,7 @@ modal/app.py,sha256=EJ7FUN6rWnSwLJoYJh8nmKg_t-8hdN8_rt0OrkP7JvQ,46084
|
|
19
19
|
modal/app.pyi,sha256=BE5SlR5tRECuc6-e2lUuOknDdov3zxgZ4N0AsLb5ZVQ,25270
|
20
20
|
modal/call_graph.py,sha256=1g2DGcMIJvRy-xKicuf63IVE98gJSnQsr8R_NVMptNc,2581
|
21
21
|
modal/client.py,sha256=VMg_aIuo_LOEe2ttxBHEND3PLhTp5lo-onH4wELhIyY,16375
|
22
|
-
modal/client.pyi,sha256=
|
22
|
+
modal/client.pyi,sha256=nmabQ_iRVi5HSDGw9_Bij5P8f2HyaMer8FOsGYGKPW4,7354
|
23
23
|
modal/cloud_bucket_mount.py,sha256=G7T7jWLD0QkmrfKR75mSTwdUZ2xNfj7pkVqb4ipmxmI,5735
|
24
24
|
modal/cloud_bucket_mount.pyi,sha256=CEi7vrH3kDUF4LAy4qP6tfImy2UJuFRcRbsgRNM1wo8,1403
|
25
25
|
modal/cls.py,sha256=F2jk5zFCAA8h-GfM0dbdBG3Mu5wiG9k9Z9JLYRYuT2Q,24758
|
@@ -82,7 +82,7 @@ modal/_runtime/user_code_imports.py,sha256=q_3JOYqCPDcVFZWCHEjyEqj8yzdFsQ49HzeqY
|
|
82
82
|
modal/_utils/__init__.py,sha256=waLjl5c6IPDhSsdWAm9Bji4e2PVxamYABKAze6CHVXY,28
|
83
83
|
modal/_utils/app_utils.py,sha256=88BT4TPLWfYAQwKTHcyzNQRHg8n9B-QE2UyJs96iV-0,108
|
84
84
|
modal/_utils/async_utils.py,sha256=CYXogDVqqUtSe-DVP2A3F-6KztjPZaW6ez2lrYBCW_Y,24917
|
85
|
-
modal/_utils/blob_utils.py,sha256=
|
85
|
+
modal/_utils/blob_utils.py,sha256=0k_qUpO5GHnz538wjRhyRw4NdJ5O322N7QSilIu32jw,16601
|
86
86
|
modal/_utils/function_utils.py,sha256=SkT5emqGJ8NNASk0BlBmgDfDBUYAkUM851K74qCHL98,24641
|
87
87
|
modal/_utils/grpc_testing.py,sha256=iqM9n5M0cWUUIIWNaEDer_pIfPnzXdZBO4L8FVbNepQ,8309
|
88
88
|
modal/_utils/grpc_utils.py,sha256=PPB5ay-vXencXNIWPVw5modr3EH7gfq2QPcO5YJ1lMU,7737
|
@@ -142,13 +142,13 @@ modal_global_objects/mounts/__init__.py,sha256=MIEP8jhXUeGq_eCjYFcqN5b1bxBM4fdk0
|
|
142
142
|
modal_global_objects/mounts/modal_client_package.py,sha256=W0E_yShsRojPzWm6LtIQqNVolapdnrZkm2hVEQuZK_4,767
|
143
143
|
modal_global_objects/mounts/python_standalone.py,sha256=_vTEX3PECUsatzhDs8lyJmDK0LbFetT1sJB6MIDfFAo,1870
|
144
144
|
modal_proto/__init__.py,sha256=MIEP8jhXUeGq_eCjYFcqN5b1bxBM4fdk0VESpjWR0fc,28
|
145
|
-
modal_proto/api.proto,sha256=
|
146
|
-
modal_proto/api_grpc.py,sha256=
|
147
|
-
modal_proto/api_pb2.py,sha256=
|
148
|
-
modal_proto/api_pb2.pyi,sha256=
|
149
|
-
modal_proto/api_pb2_grpc.py,sha256=
|
150
|
-
modal_proto/api_pb2_grpc.pyi,sha256=
|
151
|
-
modal_proto/modal_api_grpc.py,sha256=
|
145
|
+
modal_proto/api.proto,sha256=I36DzPZ4fs045HqQCEdgEiiJr1Dcd6T6fFA1RbQW7aE,78014
|
146
|
+
modal_proto/api_grpc.py,sha256=cQOfwiGd2Nyj9esTgtu39EK1QKGZJXharISgWG7_lQ8,99814
|
147
|
+
modal_proto/api_pb2.py,sha256=rk-8yxgiqsevrf8ZOQl7Elr5xKKz0nYdI46Yd6S0iJI,284335
|
148
|
+
modal_proto/api_pb2.pyi,sha256=FCMnndhn2lqdFo1kr49PjfOQzxacPg2UHM9hGpatdS8,380051
|
149
|
+
modal_proto/api_pb2_grpc.py,sha256=VTrD72cWvA2SscVVpR7w0swwGJ2O6pY-uASamt9Qm7M,215824
|
150
|
+
modal_proto/api_pb2_grpc.pyi,sha256=SbWtkTeCztsSOz8WaM07UZ5fxfKn7nQG4Dxbp5PQUz8,50356
|
151
|
+
modal_proto/modal_api_grpc.py,sha256=AUfZ2n1xOaCv-NzMp5w91fgsQi5zs79IDLH7RGOg1-o,13340
|
152
152
|
modal_proto/modal_options_grpc.py,sha256=qJ1cuwA54oRqrdTyPTbvfhFZYd9HhJKK5UCwt523r3Y,120
|
153
153
|
modal_proto/options.proto,sha256=a-siq4swVbZPfaFRXAipRZzGP2bq8OsdUvjlyzAeodQ,488
|
154
154
|
modal_proto/options_grpc.py,sha256=M18X3d-8F_cNYSVM3I25dUTO5rZ0rd-vCCfynfh13Nc,125
|
@@ -159,10 +159,10 @@ modal_proto/options_pb2_grpc.pyi,sha256=CImmhxHsYnF09iENPoe8S4J-n93jtgUYD2JPAc0y
|
|
159
159
|
modal_proto/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
160
160
|
modal_version/__init__.py,sha256=3IY-AWLH55r35_mQXIaut0jrJvoPuf1NZJBQQfSbPuo,470
|
161
161
|
modal_version/__main__.py,sha256=2FO0yYQQwDTh6udt1h-cBnGd1c4ZyHnHSI4BksxzVac,105
|
162
|
-
modal_version/_version_generated.py,sha256=
|
163
|
-
modal-0.67.
|
164
|
-
modal-0.67.
|
165
|
-
modal-0.67.
|
166
|
-
modal-0.67.
|
167
|
-
modal-0.67.
|
168
|
-
modal-0.67.
|
162
|
+
modal_version/_version_generated.py,sha256=goG3pX_4gvPQTqRGbb26U_EVKGKJ2BSJ86M2obbDDy0,149
|
163
|
+
modal-0.67.18.dist-info/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
|
164
|
+
modal-0.67.18.dist-info/METADATA,sha256=AkIw67Fd_w3r_nnsmLNl2C6uJHRSvg9o_MGK-PIBt2M,2329
|
165
|
+
modal-0.67.18.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
|
166
|
+
modal-0.67.18.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
|
167
|
+
modal-0.67.18.dist-info/top_level.txt,sha256=1nvYbOSIKcmU50fNrpnQnrrOpj269ei3LzgB6j9xGqg,64
|
168
|
+
modal-0.67.18.dist-info/RECORD,,
|
modal_proto/api.proto
CHANGED
@@ -2146,6 +2146,18 @@ message SandboxListResponse {
|
|
2146
2146
|
repeated SandboxInfo sandboxes = 1;
|
2147
2147
|
}
|
2148
2148
|
|
2149
|
+
message SandboxSnapshotFsRequest {
|
2150
|
+
string sandbox_id = 1;
|
2151
|
+
float timeout = 2;
|
2152
|
+
}
|
2153
|
+
|
2154
|
+
message SandboxSnapshotFsResponse {
|
2155
|
+
string image_id = 1;
|
2156
|
+
GenericResult result = 2;
|
2157
|
+
// Metadata may be empty since we may skip it for performance reasons.
|
2158
|
+
ImageMetadata image_metadata = 3;
|
2159
|
+
}
|
2160
|
+
|
2149
2161
|
message SandboxStdinWriteRequest {
|
2150
2162
|
string sandbox_id = 1;
|
2151
2163
|
bytes input = 2;
|
@@ -2745,6 +2757,7 @@ service ModalClient {
|
|
2745
2757
|
rpc SandboxGetTaskId(SandboxGetTaskIdRequest) returns (SandboxGetTaskIdResponse); // needed for modal container exec
|
2746
2758
|
rpc SandboxGetTunnels(SandboxGetTunnelsRequest) returns (SandboxGetTunnelsResponse);
|
2747
2759
|
rpc SandboxList(SandboxListRequest) returns (SandboxListResponse);
|
2760
|
+
rpc SandboxSnapshotFs(SandboxSnapshotFsRequest) returns (SandboxSnapshotFsResponse);
|
2748
2761
|
rpc SandboxStdinWrite(SandboxStdinWriteRequest) returns (SandboxStdinWriteResponse);
|
2749
2762
|
rpc SandboxTagsSet(SandboxTagsSetRequest) returns (google.protobuf.Empty);
|
2750
2763
|
rpc SandboxTerminate(SandboxTerminateRequest) returns (SandboxTerminateResponse);
|
modal_proto/api_grpc.py
CHANGED
@@ -389,6 +389,10 @@ class ModalClientBase(abc.ABC):
|
|
389
389
|
async def SandboxList(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.SandboxListRequest, modal_proto.api_pb2.SandboxListResponse]') -> None:
|
390
390
|
pass
|
391
391
|
|
392
|
+
@abc.abstractmethod
|
393
|
+
async def SandboxSnapshotFs(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.SandboxSnapshotFsRequest, modal_proto.api_pb2.SandboxSnapshotFsResponse]') -> None:
|
394
|
+
pass
|
395
|
+
|
392
396
|
@abc.abstractmethod
|
393
397
|
async def SandboxStdinWrite(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.SandboxStdinWriteRequest, modal_proto.api_pb2.SandboxStdinWriteResponse]') -> None:
|
394
398
|
pass
|
@@ -1093,6 +1097,12 @@ class ModalClientBase(abc.ABC):
|
|
1093
1097
|
modal_proto.api_pb2.SandboxListRequest,
|
1094
1098
|
modal_proto.api_pb2.SandboxListResponse,
|
1095
1099
|
),
|
1100
|
+
'/modal.client.ModalClient/SandboxSnapshotFs': grpclib.const.Handler(
|
1101
|
+
self.SandboxSnapshotFs,
|
1102
|
+
grpclib.const.Cardinality.UNARY_UNARY,
|
1103
|
+
modal_proto.api_pb2.SandboxSnapshotFsRequest,
|
1104
|
+
modal_proto.api_pb2.SandboxSnapshotFsResponse,
|
1105
|
+
),
|
1096
1106
|
'/modal.client.ModalClient/SandboxStdinWrite': grpclib.const.Handler(
|
1097
1107
|
self.SandboxStdinWrite,
|
1098
1108
|
grpclib.const.Cardinality.UNARY_UNARY,
|
@@ -1873,6 +1883,12 @@ class ModalClientStub:
|
|
1873
1883
|
modal_proto.api_pb2.SandboxListRequest,
|
1874
1884
|
modal_proto.api_pb2.SandboxListResponse,
|
1875
1885
|
)
|
1886
|
+
self.SandboxSnapshotFs = grpclib.client.UnaryUnaryMethod(
|
1887
|
+
channel,
|
1888
|
+
'/modal.client.ModalClient/SandboxSnapshotFs',
|
1889
|
+
modal_proto.api_pb2.SandboxSnapshotFsRequest,
|
1890
|
+
modal_proto.api_pb2.SandboxSnapshotFsResponse,
|
1891
|
+
)
|
1876
1892
|
self.SandboxStdinWrite = grpclib.client.UnaryUnaryMethod(
|
1877
1893
|
channel,
|
1878
1894
|
'/modal.client.ModalClient/SandboxStdinWrite',
|