modAL 1.2.7.dev7__py3-none-any.whl → 1.2.7.dev10__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.
@@ -43,7 +43,6 @@ from ._runtime.container_io_manager import (
43
43
  )
44
44
 
45
45
  if TYPE_CHECKING:
46
- import modal._object
47
46
  import modal._runtime.container_io_manager
48
47
  import modal._runtime.user_code_imports
49
48
 
@@ -152,12 +152,13 @@ async def perform_multipart_upload(
152
152
  part_etags = await TaskContext.gather(*upload_coros)
153
153
 
154
154
  # The body of the complete_multipart_upload command needs some data in xml format:
155
- completion_body = "<CompleteMultipartUpload>\n"
155
+ completion_parts = ["<CompleteMultipartUpload>"]
156
156
  for part_number, etag in enumerate(part_etags, 1):
157
- completion_body += f"""<Part>\n<PartNumber>{part_number}</PartNumber>\n<ETag>"{etag}"</ETag>\n</Part>\n"""
158
- completion_body += "</CompleteMultipartUpload>"
157
+ completion_parts.append(f"""<Part>\n<PartNumber>{part_number}</PartNumber>\n<ETag>"{etag}"</ETag>\n</Part>""")
158
+ completion_parts.append("</CompleteMultipartUpload>")
159
+ completion_body = "\n".join(completion_parts)
159
160
 
160
- # etag of combined object should be md5 hex of concatendated md5 *bytes* from parts + `-{num_parts}`
161
+ # etag of combined object should be md5 hex of concatenated md5 *bytes* from parts + `-{num_parts}`
161
162
  bin_hash_parts = [bytes.fromhex(etag) for etag in part_etags]
162
163
 
163
164
  expected_multipart_etag = hashlib.md5(b"".join(bin_hash_parts)).hexdigest() + f"-{len(part_etags)}"
@@ -16,8 +16,6 @@ from typing import Any, Optional, Sequence, TypeVar
16
16
  import grpclib.client
17
17
  import grpclib.config
18
18
  import grpclib.events
19
- import grpclib.protocol
20
- import grpclib.stream
21
19
  from google.protobuf.message import Message
22
20
  from google.protobuf.symbol_database import SymbolDatabase
23
21
  from grpclib import GRPCError, Status
@@ -1,5 +1,4 @@
1
1
  # Copyright Modal Labs 2022
2
- import importlib
3
2
  import importlib.util
4
3
  import typing
5
4
  from importlib.metadata import PackageNotFoundError, files
@@ -521,3 +521,17 @@ class TaskCommandRouterClient:
521
521
  await sleep_and_update_delay_and_num_retries_remaining(e)
522
522
  else:
523
523
  raise ConnectionError(str(e))
524
+
525
+ async def mount_image(self, request: sr_pb2.TaskMountDirectoryRequest):
526
+ with grpc_error_converter():
527
+ return await call_with_retries_on_transient_errors(
528
+ lambda: self._call_with_auth_retry(self._stub.TaskMountDirectory, request)
529
+ )
530
+
531
+ async def snapshot_directory(
532
+ self, request: sr_pb2.TaskSnapshotDirectoryRequest
533
+ ) -> sr_pb2.TaskSnapshotDirectoryResponse:
534
+ with grpc_error_converter():
535
+ return await call_with_retries_on_transient_errors(
536
+ lambda: self._call_with_auth_retry(self._stub.TaskSnapshotDirectory, request)
537
+ )
modal/client.pyi CHANGED
@@ -32,7 +32,7 @@ class _Client:
32
32
  server_url: str,
33
33
  client_type: int,
34
34
  credentials: typing.Optional[tuple[str, str]],
35
- version: str = "1.2.7.dev7",
35
+ version: str = "1.2.7.dev10",
36
36
  ):
37
37
  """mdmd:hidden
38
38
  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.2.7.dev7",
166
+ version: str = "1.2.7.dev10",
167
167
  ):
168
168
  """mdmd:hidden
169
169
  The Modal client object is not intended to be instantiated directly by users.
modal/file_io.py CHANGED
@@ -190,7 +190,7 @@ class _FileIO(Generic[T]):
190
190
 
191
191
  async def _wait(self, exec_id: str) -> bytes:
192
192
  # The logic here is similar to how output is read from `exec`
193
- output = b""
193
+ output_buffer = io.BytesIO()
194
194
  completed = False
195
195
  retries_remaining = 10
196
196
  while not completed:
@@ -201,7 +201,7 @@ class _FileIO(Generic[T]):
201
201
  break
202
202
  if isinstance(data, Exception):
203
203
  raise data
204
- output += data
204
+ output_buffer.write(data)
205
205
  except (GRPCError, StreamTerminatedError) as exc:
206
206
  if retries_remaining > 0:
207
207
  retries_remaining -= 1
@@ -212,7 +212,7 @@ class _FileIO(Generic[T]):
212
212
  elif isinstance(exc, StreamTerminatedError):
213
213
  continue
214
214
  raise
215
- return output
215
+ return output_buffer.getvalue()
216
216
 
217
217
  def _validate_type(self, data: Union[bytes, str]) -> None:
218
218
  if self._binary and isinstance(data, str):
@@ -421,10 +421,22 @@ class _FileIO(Generic[T]):
421
421
  task_id=self._task_id,
422
422
  ),
423
423
  )
424
+
425
+ def end_of_event(item: bytes, buffer: io.BytesIO, boundary_token: bytes) -> bool:
426
+ if not item.endswith(b"\n"):
427
+ return False
428
+ boundary_token_size = len(boundary_token)
429
+ if buffer.tell() < boundary_token_size:
430
+ return False
431
+ buffer.seek(-boundary_token_size, io.SEEK_END)
432
+ if buffer.read(boundary_token_size) == boundary_token:
433
+ return True
434
+ return False
435
+
424
436
  async with TaskContext() as tc:
425
437
  tc.create_task(self._consume_watch_output(resp.exec_id))
426
438
 
427
- buffer = b""
439
+ item_buffer = io.BytesIO()
428
440
  while True:
429
441
  if len(self._watch_output_buffer) > 0:
430
442
  item = self._watch_output_buffer.pop(0)
@@ -432,12 +444,12 @@ class _FileIO(Generic[T]):
432
444
  break
433
445
  if isinstance(item, Exception):
434
446
  raise item
435
- buffer += item
436
- # a single event may be split across multiple messages
437
- # the end of an event is marked by two newlines
438
- if buffer.endswith(b"\n\n"):
447
+ item_buffer.write(item)
448
+ assert isinstance(item, bytes)
449
+ # Single events may span multiple messages so we need to check for a special event boundary token
450
+ if end_of_event(item, item_buffer, boundary_token=b"\n\n"):
439
451
  try:
440
- event_json = json.loads(buffer.strip().decode())
452
+ event_json = json.loads(item_buffer.getvalue().strip().decode())
441
453
  event = FileWatchEvent(
442
454
  type=FileWatchEventType(event_json["event_type"]),
443
455
  paths=event_json["paths"],
@@ -447,7 +459,7 @@ class _FileIO(Generic[T]):
447
459
  except (json.JSONDecodeError, KeyError, ValueError):
448
460
  # skip invalid events
449
461
  pass
450
- buffer = b""
462
+ item_buffer = io.BytesIO()
451
463
  else:
452
464
  await asyncio.sleep(0.1)
453
465
 
modal/image.py CHANGED
@@ -874,6 +874,7 @@ class _Image(_Object, type_prefix="im"):
874
874
 
875
875
  rep = f"Image.from_id({image_id!r})"
876
876
  obj = _Image._from_loader(_load, rep, load_context_overrides=LoadContext(client=client))
877
+ obj._object_id = image_id
877
878
 
878
879
  return obj
879
880
 
modal/io_streams.py CHANGED
@@ -23,7 +23,7 @@ from grpclib.exceptions import GRPCError, StreamTerminatedError
23
23
  from modal.exception import ClientClosed, ExecTimeoutError, InvalidError
24
24
  from modal_proto import api_pb2
25
25
 
26
- from ._utils.async_utils import aclosing, synchronize_api
26
+ from ._utils.async_utils import aclosing, synchronize_api, synchronizer
27
27
  from ._utils.grpc_utils import RETRYABLE_GRPC_STATUS_CODES
28
28
  from ._utils.task_command_router_client import TaskCommandRouterClient
29
29
  from .client import _Client
@@ -153,17 +153,17 @@ class _StreamReaderThroughServer(Generic[T]):
153
153
  """Fetch the entire contents of the stream until EOF."""
154
154
  logger.debug(f"{self._object_id} StreamReader fd={self._file_descriptor} read starting")
155
155
  if self._text:
156
- data_str = ""
156
+ buffer = io.StringIO()
157
157
  async for message in _decode_bytes_stream_to_str(self._get_logs()):
158
- data_str += message
158
+ buffer.write(message)
159
159
  logger.debug(f"{self._object_id} StreamReader fd={self._file_descriptor} read completed after EOF")
160
- return cast(T, data_str)
160
+ return cast(T, buffer.getvalue())
161
161
  else:
162
- data_bytes = b""
162
+ buffer = io.BytesIO()
163
163
  async for message in self._get_logs():
164
- data_bytes += message
164
+ buffer.write(message)
165
165
  logger.debug(f"{self._object_id} StreamReader fd={self._file_descriptor} read completed after EOF")
166
- return cast(T, data_bytes)
166
+ return cast(T, buffer.getvalue())
167
167
 
168
168
  async def _consume_container_process_stream(self):
169
169
  """Consume the container process stream and store messages in the buffer."""
@@ -566,6 +566,9 @@ class _StreamReader(Generic[T]):
566
566
  task_id: Optional[str] = None,
567
567
  ) -> None:
568
568
  """mdmd:hidden"""
569
+ # we can remove this once we ensure no constructors use async code
570
+ assert asyncio.get_running_loop() == synchronizer._get_loop(start=False)
571
+
569
572
  if by_line and not text:
570
573
  raise ValueError("line-buffering is only supported when text=True")
571
574
 
modal/sandbox.py CHANGED
@@ -6,6 +6,7 @@ import time
6
6
  import uuid
7
7
  from collections.abc import AsyncGenerator, Collection, Sequence
8
8
  from dataclasses import dataclass
9
+ from pathlib import PurePosixPath
9
10
  from typing import TYPE_CHECKING, Any, AsyncIterator, Literal, Optional, Union, overload
10
11
 
11
12
  from ._pty import get_pty_info
@@ -600,6 +601,49 @@ class _Sandbox(_Object, type_prefix="sb"):
600
601
 
601
602
  return image
602
603
 
604
+ async def _experimental_mount_image(self, path: Union[PurePosixPath, str], image: Optional[_Image]):
605
+ """Mount an Image at a path in the Sandbox filesystem."""
606
+
607
+ image_id = None
608
+
609
+ if image:
610
+ if not image._object_id:
611
+ # FIXME
612
+ raise InvalidError("Image has not been built.")
613
+ image_id = image._object_id
614
+ else:
615
+ image_id = "" # empty string indicates mount an empty dir
616
+
617
+ task_id = await self._get_task_id()
618
+ if (command_router_client := await self._get_command_router_client(task_id)) is None:
619
+ raise InvalidError("Mounting directories requires direct Sandbox control - please contact Modal support.")
620
+
621
+ posix_path = PurePosixPath(path)
622
+ if not posix_path.is_absolute():
623
+ raise InvalidError(f"Mount path must be absolute; got: {posix_path}")
624
+ path_bytes = posix_path.as_posix().encode("utf8")
625
+
626
+ req = sr_pb2.TaskMountDirectoryRequest(task_id=task_id, path=path_bytes, image_id=image_id)
627
+ await command_router_client.mount_image(req)
628
+
629
+ async def _experimental_snapshot_directory(self, path: Union[PurePosixPath, str]) -> _Image:
630
+ """Snapshot local changes to a previously mounted Image, creating a new Image."""
631
+
632
+ task_id = await self._get_task_id()
633
+ if (command_router_client := await self._get_command_router_client(task_id)) is None:
634
+ raise InvalidError(
635
+ "Snapshotting directories requires direct Sandbox control - please contact Modal support."
636
+ )
637
+
638
+ posix_path = PurePosixPath(path)
639
+ if not posix_path.is_absolute():
640
+ raise InvalidError(f"Snapshot path must be absolute; got: {posix_path}")
641
+ path_bytes = posix_path.as_posix().encode("utf8")
642
+
643
+ req = sr_pb2.TaskSnapshotDirectoryRequest(task_id=task_id, path=path_bytes)
644
+ res = await command_router_client.snapshot_directory(req)
645
+ return _Image._new_hydrated(res.image_id, self._client, None)
646
+
603
647
  # Live handle methods
604
648
 
605
649
  async def wait(self, raise_on_termination: bool = True):
modal/sandbox.pyi CHANGED
@@ -22,6 +22,7 @@ import modal.stream_type
22
22
  import modal.volume
23
23
  import modal_proto.api_pb2
24
24
  import os
25
+ import pathlib
25
26
  import typing
26
27
  import typing_extensions
27
28
 
@@ -254,6 +255,18 @@ class _Sandbox(modal._object._Object):
254
255
  """
255
256
  ...
256
257
 
258
+ async def _experimental_mount_image(
259
+ self, path: typing.Union[pathlib.PurePosixPath, str], image: typing.Optional[modal.image._Image]
260
+ ):
261
+ """Mount an Image at a path in the Sandbox filesystem."""
262
+ ...
263
+
264
+ async def _experimental_snapshot_directory(
265
+ self, path: typing.Union[pathlib.PurePosixPath, str]
266
+ ) -> modal.image._Image:
267
+ """Snapshot local changes to a previously mounted Image, creating a new Image."""
268
+ ...
269
+
257
270
  async def wait(self, raise_on_termination: bool = True):
258
271
  """Wait for the Sandbox to finish running."""
259
272
  ...
@@ -820,6 +833,32 @@ class Sandbox(modal.object.Object):
820
833
 
821
834
  snapshot_filesystem: __snapshot_filesystem_spec[typing_extensions.Self]
822
835
 
836
+ class ___experimental_mount_image_spec(typing_extensions.Protocol[SUPERSELF]):
837
+ def __call__(
838
+ self, /, path: typing.Union[pathlib.PurePosixPath, str], image: typing.Optional[modal.image.Image]
839
+ ):
840
+ """Mount an Image at a path in the Sandbox filesystem."""
841
+ ...
842
+
843
+ async def aio(
844
+ self, /, path: typing.Union[pathlib.PurePosixPath, str], image: typing.Optional[modal.image.Image]
845
+ ):
846
+ """Mount an Image at a path in the Sandbox filesystem."""
847
+ ...
848
+
849
+ _experimental_mount_image: ___experimental_mount_image_spec[typing_extensions.Self]
850
+
851
+ class ___experimental_snapshot_directory_spec(typing_extensions.Protocol[SUPERSELF]):
852
+ def __call__(self, /, path: typing.Union[pathlib.PurePosixPath, str]) -> modal.image.Image:
853
+ """Snapshot local changes to a previously mounted Image, creating a new Image."""
854
+ ...
855
+
856
+ async def aio(self, /, path: typing.Union[pathlib.PurePosixPath, str]) -> modal.image.Image:
857
+ """Snapshot local changes to a previously mounted Image, creating a new Image."""
858
+ ...
859
+
860
+ _experimental_snapshot_directory: ___experimental_snapshot_directory_spec[typing_extensions.Self]
861
+
823
862
  class __wait_spec(typing_extensions.Protocol[SUPERSELF]):
824
863
  def __call__(self, /, raise_on_termination: bool = True):
825
864
  """Wait for the Sandbox to finish running."""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.2.7.dev7
3
+ Version: 1.2.7.dev10
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License: Apache-2.0
@@ -3,7 +3,7 @@ modal/__main__.py,sha256=UTyagD6NHFl3hdmKVr4yXGGB5_Gzj3NjrpuTIwJ25Tw,1597
3
3
  modal/_billing.py,sha256=C1jUN9f_1WqozSZAt9EOk1nImXUdiLrgFeeAu3R23cI,3012
4
4
  modal/_clustered_functions.py,sha256=7amiOxErtlciWeBJBL2KvaxerUomJpTAJ3qElflFHQA,2884
5
5
  modal/_clustered_functions.pyi,sha256=JmYwAGOLEnD5AF-gYF9O5tu-SgGjeoJz-X1j48b1Ijg,1157
6
- modal/_container_entrypoint.py,sha256=aRuWG1xl3kDy28CfQrqQ-LU8liX2W_bwm2avVOE63Tw,19812
6
+ modal/_container_entrypoint.py,sha256=aatoboeM3fe9w7DVdCgVOhW4iW9EwduZwiVS3ri0HgA,19787
7
7
  modal/_functions.py,sha256=VqhEE8cctHkonWvtdXOCYnW06TvXPTV1ONeIMoR1SFA,91262
8
8
  modal/_grpc_client.py,sha256=9Yv_aidXWrvcbIYWNpRXUPqEHMvNsYRCSvRrGcVbtPc,6928
9
9
  modal/_ipython.py,sha256=TW1fkVOmZL3YYqdS2YlM1hqpf654Yf8ZyybHdBnlhSw,301
@@ -26,7 +26,7 @@ modal/app.pyi,sha256=rL-UAzRkwoQp-PA96fQAS4YfmjWBDyfasziCMq6NrHI,51015
26
26
  modal/billing.py,sha256=zmQ3bcCJlwa4KD1IA_QgdWpm1pn13c-7qfy79iEauYI,195
27
27
  modal/call_graph.py,sha256=1g2DGcMIJvRy-xKicuf63IVE98gJSnQsr8R_NVMptNc,2581
28
28
  modal/client.py,sha256=k1CqQ_0t4-vHylkqYZgYCnClg-FT0QrTPAKivL01A_k,14354
29
- modal/client.pyi,sha256=iDYFbDtM2tc7Sx9WkenkYajql1W5XCmwYk5QETBzolU,13146
29
+ modal/client.pyi,sha256=aHO24dFfbr5m-aTqFZ-8VLgciKD9XRF1_VH_0Gno1rk,13148
30
30
  modal/cloud_bucket_mount.py,sha256=cvVj5Rt4nDHoQbTneoJPTaAcnl_Ab_mrsjnnzd0v9OI,6013
31
31
  modal/cloud_bucket_mount.pyi,sha256=vXusGMOUk9HjCs4lhxteuCK4xLQclPfugGWKo7LECEA,7539
32
32
  modal/cls.py,sha256=PIGe4ED28jcxC2HeKtMD3odMIb4qNmlRt3tj1dZstRo,41738
@@ -39,15 +39,15 @@ modal/dict.pyi,sha256=yQHHZe98M6gB2ahzrmqlq8KUXvqFy6vamsijI2H0RdE,32002
39
39
  modal/environments.py,sha256=wMiMNpPkvIl_BdxRb81CY9Djzhczp_y4GEYKWp0JyBc,6135
40
40
  modal/environments.pyi,sha256=bMIxvwahckgaolGD3-hP2iovRHDXewvgbVs_nx4ze0o,3808
41
41
  modal/exception.py,sha256=8QeIE6XcuAc1moa1hSgQTxFFjfEyIdiuKiAyCS3RS4M,10210
42
- modal/file_io.py,sha256=lfcQAWeuujQol_e1mYlm331Uesh__yWsv-u19gQV7wc,19308
42
+ modal/file_io.py,sha256=hqK7ZXo7iEidXRriBAU2Es08HC-rGKmMjMbcT5FaASI,19939
43
43
  modal/file_io.pyi,sha256=MpO5-EA6KuBbOQV0zXV_nPDD5Aw5dfYVa8q9SGBsAVM,14666
44
44
  modal/file_pattern_matcher.py,sha256=A_Kdkej6q7YQyhM_2-BvpFmPqJ0oHb54B6yf9VqvPVE,8116
45
45
  modal/functions.py,sha256=kcNHvqeGBxPI7Cgd57NIBBghkfbeFJzXO44WW0jSmao,325
46
46
  modal/functions.pyi,sha256=CeSVZcrjsjh8Gqo5PK7QkbpfSlrKvnFzm3HLYqGEePw,38107
47
47
  modal/gpu.py,sha256=Fe5ORvVPDIstSq1xjmM6OoNgLYFWvogP9r5BgmD3hYg,6769
48
- modal/image.py,sha256=Pm26DwuD7RqfrxscAHxhoA9LGJYTt_k0wcsHRqbwnzE,107945
48
+ modal/image.py,sha256=_NsWCNzxCxgKko-1bYSwDpy9w8Jnj5Qxo5grNe6WdAY,107979
49
49
  modal/image.pyi,sha256=grkqK9BfyKDXmJYNme-lGa0O3u7pOU5GifyLOAhG3sc,78202
50
- modal/io_streams.py,sha256=ziMQ1VNxxj0tJPYl9QpJZCWd72jyQ9BJ1mmanPXvxv0,30615
50
+ modal/io_streams.py,sha256=jhBdJH080kPkNdkYyvtxJumcJt2nEDozsKDF5I0o3hM,30818
51
51
  modal/io_streams.pyi,sha256=GGRPHumOaTwr11GzmZPf4_aSXGGKsMvB6NoSGHp_F7Q,18633
52
52
  modal/mount.py,sha256=NYWmSqK842qmYUQZqaacwCdMRRyfj8stA3DvsChjGRc,33838
53
53
  modal/mount.pyi,sha256=cJ4HPB7Oa7vl_AkBWQ0cKaty36ZcO8fNLE48DYUa9eQ,15807
@@ -69,8 +69,8 @@ modal/retries.py,sha256=IvNLDM0f_GLUDD5VgEDoN09C88yoxSrCquinAuxT1Sc,5205
69
69
  modal/runner.py,sha256=T-QUi4IykPxCu6TqzJtBdqQvwiIuysstaAL01SEQ9tA,25592
70
70
  modal/runner.pyi,sha256=HYBi04nUrZN9-L-cTlvDDHFiJS-N6M3usKk1_QzGnpc,8736
71
71
  modal/running_app.py,sha256=v61mapYNV1-O-Uaho5EfJlryMLvIT9We0amUOSvSGx8,1188
72
- modal/sandbox.py,sha256=IHiNLWYYryjO3kvwBIqwCD8bqdShsayKyiPeBB2C0g4,48715
73
- modal/sandbox.pyi,sha256=nIA8TrSQAM8IJemkLOROjLJ5vGg7bj-g0Cwm7RcZiEg,56475
72
+ modal/sandbox.py,sha256=i6ZgkxmmonuvBE-A-PCSjyO_EZrNAsOgLc39gcbb14k,50777
73
+ modal/sandbox.pyi,sha256=oFarWaYY39ZMX-vXpRJJIOPiAhhHB6EUyTpDp2mt19o,58214
74
74
  modal/schedule.py,sha256=ng0g0AqNY5GQI9KhkXZQ5Wam5G42glbkqVQsNpBtbDE,3078
75
75
  modal/scheduler_placement.py,sha256=BAREdOY5HzHpzSBqt6jDVR6YC_jYfHMVqOzkyqQfngU,1235
76
76
  modal/secret.py,sha256=NrsC2sA4kkep1pI2GIS5mD0ah_zpu9Mvcw2rcHNCzlM,18178
@@ -98,25 +98,25 @@ modal/_utils/__init__.py,sha256=waLjl5c6IPDhSsdWAm9Bji4e2PVxamYABKAze6CHVXY,28
98
98
  modal/_utils/app_utils.py,sha256=88BT4TPLWfYAQwKTHcyzNQRHg8n9B-QE2UyJs96iV-0,108
99
99
  modal/_utils/async_utils.py,sha256=PnwHfaHcqjLwMnlGC2kn8nqubxpXcSKcy4jHx6477dg,30625
100
100
  modal/_utils/auth_token_manager.py,sha256=QsDokl1c1dN9m6Z9N-Se-8cY3laphByjJtNdRXUTieI,5151
101
- modal/_utils/blob_utils.py,sha256=4z0qH5txEUvfmfIYnZnvIG6G4BwiTpn3fsfI24ppD6M,23316
101
+ modal/_utils/blob_utils.py,sha256=L4lEL-rvZwoxCxrGaa8zWVoaHjhq1eQfO4SLrvt4g8k,23376
102
102
  modal/_utils/bytes_io_segment_payload.py,sha256=vaXPq8b52-x6G2hwE7SrjS58pg_aRm7gV3bn3yjmTzQ,4261
103
103
  modal/_utils/deprecation.py,sha256=-Bgg7jZdcJU8lROy18YyVnQYbM8hue-hVmwJqlWAGH0,5504
104
104
  modal/_utils/docker_utils.py,sha256=h1uETghR40mp_y3fSWuZAfbIASH1HMzuphJHghAL6DU,3722
105
105
  modal/_utils/function_utils.py,sha256=kBMS4tGarKSKomp4BoxnmaNQ3nu72nodZ05Puqq5gUs,28361
106
106
  modal/_utils/git_utils.py,sha256=qtUU6JAttF55ZxYq51y55OR58B0tDPZsZWK5dJe6W5g,3182
107
107
  modal/_utils/grpc_testing.py,sha256=H1zHqthv19eGPJz2HKXDyWXWGSqO4BRsxah3L5Xaa8A,8619
108
- modal/_utils/grpc_utils.py,sha256=Cs8KRV682_R6W25cbz-e5R4LRJ4WA5OR9Plj8qIh3x4,16325
108
+ modal/_utils/grpc_utils.py,sha256=2Q88G0u22q4yo91Ud1SfxPF9YoR7C-YDU2e__KTMNp8,16279
109
109
  modal/_utils/hash_utils.py,sha256=zg3J6OGxTFGSFri1qQ12giDz90lWk8bzaxCTUCRtiX4,3034
110
110
  modal/_utils/http_utils.py,sha256=yeTFsXYr0rYMEhB7vBP7audG9Uc7OLhzKBANFDZWVt0,2451
111
111
  modal/_utils/jwt_utils.py,sha256=fxH9plyrbAemTbjSsQtzIdDXE9QXxvMC4DiUZ16G0aA,1360
112
112
  modal/_utils/logger.py,sha256=NgbMKFT9chYYt_TU01DdIior5ByYr2gZtrWIk1SFRLc,1782
113
113
  modal/_utils/mount_utils.py,sha256=3v6wbSvEjOhIlnLGbyXKOzdoXaG-FwNAZ_Rr0io_v2o,4113
114
114
  modal/_utils/name_utils.py,sha256=CIQL0Y4z47tq0rfNL2Kdo5dxsGrxoN2hR9Ko0HapeE4,2517
115
- modal/_utils/package_utils.py,sha256=LcL2olGN4xaUzu2Tbv-C-Ft9Qp6bsLxEfETOAVd-mjU,2073
115
+ modal/_utils/package_utils.py,sha256=jYE7WFVzYWIfO0ZJhno_BYHb6Skp48uupOiw1a3yWzw,2056
116
116
  modal/_utils/pattern_utils.py,sha256=ZUffaECfe2iYBhH6cvCB-0-UWhmEBTZEl_TwG_So3ag,6714
117
117
  modal/_utils/rand_pb_testing.py,sha256=mmVPk1rZldHwHZx0DnHTuHQlRLAiiAYdxjwEJpxvT9c,3900
118
118
  modal/_utils/shell_utils.py,sha256=hWHzv730Br2Xyj6cGPiMZ-198Z3RZuOu3pDXhFSZ22c,2157
119
- modal/_utils/task_command_router_client.py,sha256=amgcxvgJoVC0zkwyOoa3kQg6UXxdt3DlcnbxZRIU6iQ,23328
119
+ modal/_utils/task_command_router_client.py,sha256=Ua1WoNEH0Tdi1skLFZ8dJ5I2aq95zaup9MLlL0hsIdw,23961
120
120
  modal/_utils/time_utils.py,sha256=43tpFVwT7ykOjlETIFLVt9auMsRZqYYRYBEKxGCrRSA,1212
121
121
  modal/_vendor/__init__.py,sha256=MIEP8jhXUeGq_eCjYFcqN5b1bxBM4fdk0VESpjWR0fc,28
122
122
  modal/_vendor/a2wsgi_wsgi.py,sha256=Q1AsjpV_Q_vzQsz_cSqmP9jWzsGsB-ARFU6vpQYml8k,21878
@@ -158,7 +158,7 @@ modal/experimental/__init__.py,sha256=GOuo3t4-Le0ZVddiHIOw0MQxkdTJge-bVbhDvgnblm
158
158
  modal/experimental/flash.py,sha256=GJZwSr-4OHlP6gCIZdcbsSb8D8WX9xJwMphjwcfsRoU,31262
159
159
  modal/experimental/flash.pyi,sha256=q4a3mdgL0jzATPL2tS7LpuyulYzF1vUSE453S9xc8n8,16965
160
160
  modal/experimental/ipython.py,sha256=TrCfmol9LGsRZMeDoeMPx3Hv3BFqQhYnmD_iH0pqdhk,2904
161
- modal-1.2.7.dev7.dist-info/licenses/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
161
+ modal-1.2.7.dev10.dist-info/licenses/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
162
162
  modal_docs/__init__.py,sha256=svYKtV8HDwDCN86zbdWqyq5T8sMdGDj0PVlzc2tIxDM,28
163
163
  modal_docs/gen_cli_docs.py,sha256=c1yfBS_x--gL5bs0N4ihMwqwX8l3IBWSkBAKNNIi6bQ,3801
164
164
  modal_docs/gen_reference_docs.py,sha256=d_CQUGQ0rfw28u75I2mov9AlS773z9rG40-yq5o7g2U,6359
@@ -180,10 +180,10 @@ modal_proto/task_command_router_pb2.py,sha256=2Y8wRvnq4_7RiQ-5ZAPIgXaxrHv_MXzgS5
180
180
  modal_proto/task_command_router_pb2.pyi,sha256=yI4tFteErLlonFA2HyaWtONfhY_VGSe7KCWFIspvmkE,16323
181
181
  modal_proto/task_command_router_pb2_grpc.py,sha256=q2VWfK2-4uDcPaPLhAqPZkgxhuQRYnWmwUcnEbPbGuk,13895
182
182
  modal_proto/task_command_router_pb2_grpc.pyi,sha256=e1MM10VGUgDkm041v53QeTglGQPzTpA0FUsFtezjp74,4536
183
- modal_version/__init__.py,sha256=EIU8WY6zGrQ5WjfZUZ42Hl3spbaZh3QHRY0P_2zdMb8,120
183
+ modal_version/__init__.py,sha256=zyKrlYMjpwrwiya16pRb-7K3NCD1dIssFEmawq1m2aI,121
184
184
  modal_version/__main__.py,sha256=nLUbubxKx7GXNzJIkTB7M7_u8080LyLM0IS0rzFkC_c,119
185
- modal-1.2.7.dev7.dist-info/METADATA,sha256=FpCHbZMv2nPWKfnWIBQ7nXtlMtihMgF0eImXNNBNFK8,2491
186
- modal-1.2.7.dev7.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
187
- modal-1.2.7.dev7.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
188
- modal-1.2.7.dev7.dist-info/top_level.txt,sha256=4BWzoKYREKUZ5iyPzZpjqx4G8uB5TWxXPDwibLcVa7k,43
189
- modal-1.2.7.dev7.dist-info/RECORD,,
185
+ modal-1.2.7.dev10.dist-info/METADATA,sha256=Frl579v54TJjA_50lpnE7SAv75E-o6CCuLSjU3V2ibM,2492
186
+ modal-1.2.7.dev10.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
187
+ modal-1.2.7.dev10.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
188
+ modal-1.2.7.dev10.dist-info/top_level.txt,sha256=4BWzoKYREKUZ5iyPzZpjqx4G8uB5TWxXPDwibLcVa7k,43
189
+ modal-1.2.7.dev10.dist-info/RECORD,,
modal_version/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
1
  # Copyright Modal Labs 2025
2
2
  """Supplies the current version of the modal client library."""
3
3
 
4
- __version__ = "1.2.7.dev7"
4
+ __version__ = "1.2.7.dev10"