modal 0.66.28__py3-none-any.whl → 0.66.30__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/app.py CHANGED
@@ -487,7 +487,7 @@ class _App:
487
487
  *self._mounts,
488
488
  ]
489
489
  for function in self.registered_functions.values():
490
- all_mounts.extend(function._used_local_mounts)
490
+ all_mounts.extend(function._serve_mounts)
491
491
 
492
492
  return [m for m in all_mounts if m.is_local()]
493
493
 
modal/client.pyi CHANGED
@@ -31,7 +31,7 @@ class _Client:
31
31
  server_url: str,
32
32
  client_type: int,
33
33
  credentials: typing.Optional[typing.Tuple[str, str]],
34
- version: str = "0.66.28",
34
+ version: str = "0.66.30",
35
35
  ): ...
36
36
  def is_closed(self) -> bool: ...
37
37
  @property
@@ -90,7 +90,7 @@ class Client:
90
90
  server_url: str,
91
91
  client_type: int,
92
92
  credentials: typing.Optional[typing.Tuple[str, str]],
93
- version: str = "0.66.28",
93
+ version: str = "0.66.30",
94
94
  ): ...
95
95
  def is_closed(self) -> bool: ...
96
96
  @property
modal/functions.py CHANGED
@@ -304,7 +304,7 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
304
304
 
305
305
  # TODO: more type annotations
306
306
  _info: Optional[FunctionInfo]
307
- _used_local_mounts: typing.FrozenSet[_Mount] # set at load time, only by loader
307
+ _serve_mounts: typing.FrozenSet[_Mount] # set at load time, only by loader
308
308
  _app: Optional["modal.app._App"] = None
309
309
  _obj: Optional["modal.cls._Obj"] = None # only set for InstanceServiceFunctions and bound instance methods
310
310
  _web_url: Optional[str]
@@ -579,6 +579,7 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
579
579
 
580
580
  if is_local():
581
581
  entrypoint_mounts = info.get_entrypoint_mount()
582
+
582
583
  all_mounts = [
583
584
  _get_client_mount(),
584
585
  *explicit_mounts,
@@ -611,6 +612,7 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
611
612
  if proxy:
612
613
  # HACK: remove this once we stop using ssh tunnels for this.
613
614
  if image:
615
+ # TODO(elias): this will cause an error if users use prior `.add_local_*` commands without copy=True
614
616
  image = image.apt_install("autossh")
615
617
 
616
618
  function_spec = _FunctionSpec(
@@ -827,7 +829,7 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
827
829
  )
828
830
  for path, volume in validated_volumes
829
831
  ]
830
- loaded_mount_ids = {m.object_id for m in all_mounts}
832
+ loaded_mount_ids = {m.object_id for m in all_mounts} | {m.object_id for m in image._mount_layers}
831
833
 
832
834
  # Get object dependencies
833
835
  object_dependencies = []
@@ -969,9 +971,9 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
969
971
  raise InvalidError(f"Function {info.function_name} is too large to deploy.")
970
972
  raise
971
973
  function_creation_status.set_response(response)
972
- local_mounts = set(m for m in all_mounts if m.is_local()) # needed for modal.serve file watching
973
- local_mounts |= image._used_local_mounts
974
- obj._used_local_mounts = frozenset(local_mounts)
974
+ serve_mounts = set(m for m in all_mounts if m.is_local()) # needed for modal.serve file watching
975
+ serve_mounts |= image._serve_mounts
976
+ obj._serve_mounts = frozenset(serve_mounts)
975
977
  self._hydrate(response.function_id, resolver.client, response.handle_metadata)
976
978
 
977
979
  rep = f"Function({tag})"
@@ -1222,7 +1224,7 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
1222
1224
  self._function_name = None
1223
1225
  self._info = None
1224
1226
  self._use_function_id = ""
1225
- self._used_local_mounts = frozenset()
1227
+ self._serve_mounts = frozenset()
1226
1228
 
1227
1229
  def _hydrate_metadata(self, metadata: Optional[Message]):
1228
1230
  # Overridden concrete implementation of base class method
modal/functions.pyi CHANGED
@@ -110,7 +110,7 @@ OriginalReturnType = typing.TypeVar("OriginalReturnType", covariant=True)
110
110
 
111
111
  class _Function(typing.Generic[P, ReturnType, OriginalReturnType], modal.object._Object):
112
112
  _info: typing.Optional[modal._utils.function_utils.FunctionInfo]
113
- _used_local_mounts: typing.FrozenSet[modal.mount._Mount]
113
+ _serve_mounts: typing.FrozenSet[modal.mount._Mount]
114
114
  _app: typing.Optional[modal.app._App]
115
115
  _obj: typing.Optional[modal.cls._Obj]
116
116
  _web_url: typing.Optional[str]
@@ -286,7 +286,7 @@ P_INNER = typing_extensions.ParamSpec("P_INNER")
286
286
 
287
287
  class Function(typing.Generic[P, ReturnType, OriginalReturnType], modal.object.Object):
288
288
  _info: typing.Optional[modal._utils.function_utils.FunctionInfo]
289
- _used_local_mounts: typing.FrozenSet[modal.mount.Mount]
289
+ _serve_mounts: typing.FrozenSet[modal.mount.Mount]
290
290
  _app: typing.Optional[modal.app.App]
291
291
  _obj: typing.Optional[modal.cls.Obj]
292
292
  _web_url: typing.Optional[str]
modal/image.py CHANGED
@@ -273,12 +273,24 @@ class _Image(_Object, type_prefix="im"):
273
273
 
274
274
  force_build: bool
275
275
  inside_exceptions: List[Exception]
276
- _used_local_mounts: typing.FrozenSet[_Mount] # used for mounts watching
276
+ _serve_mounts: typing.FrozenSet[_Mount] # used for mounts watching in `modal serve`
277
+ _deferred_mounts: Sequence[
278
+ _Mount
279
+ ] # added as mounts on any container referencing the Image, see `def _mount_layers`
277
280
  _metadata: Optional[api_pb2.ImageMetadata] = None # set on hydration, private for now
278
281
 
279
282
  def _initialize_from_empty(self):
280
283
  self.inside_exceptions = []
281
- self._used_local_mounts = frozenset()
284
+ self._serve_mounts = frozenset()
285
+ self._deferred_mounts = ()
286
+ self.force_build = False
287
+
288
+ def _initialize_from_other(self, other: "_Image"):
289
+ # used by .clone()
290
+ self.inside_exceptions = other.inside_exceptions
291
+ self.force_build = other.force_build
292
+ self._serve_mounts = other._serve_mounts
293
+ self._deferred_mounts = other._deferred_mounts
282
294
 
283
295
  def _hydrate_metadata(self, message: Optional[Message]):
284
296
  env_image_id = config.get("image_id") # set as an env var in containers
@@ -292,6 +304,51 @@ class _Image(_Object, type_prefix="im"):
292
304
  assert isinstance(message, api_pb2.ImageMetadata)
293
305
  self._metadata = message
294
306
 
307
+ def _add_mount_layer_or_copy(self, mount: _Mount, copy: bool = False):
308
+ if copy:
309
+ return self.copy_mount(mount, remote_path="/")
310
+
311
+ base_image = self
312
+
313
+ async def _load(self2: "_Image", resolver: Resolver, existing_object_id: Optional[str]):
314
+ self2._hydrate_from_other(base_image) # same image id as base image as long as it's lazy
315
+ self2._deferred_mounts = tuple(base_image._deferred_mounts) + (mount,)
316
+ self2._serve_mounts = base_image._serve_mounts | ({mount} if mount.is_local() else set())
317
+
318
+ return _Image._from_loader(_load, "Image(local files)", deps=lambda: [base_image, mount])
319
+
320
+ @property
321
+ def _mount_layers(self) -> typing.Tuple[_Mount]:
322
+ """Non-evaluated mount layers on the image
323
+
324
+ When the image is used by a Modal container, these mounts need to be attached as well to
325
+ represent the full image content, as they haven't yet been represented as a layer in the
326
+ image.
327
+
328
+ When the image is used as a base image for a new layer (that is not itself a mount layer)
329
+ these mounts need to first be inserted as a copy operation (.copy_mount) into the image.
330
+ """
331
+ return self._deferred_mounts
332
+
333
+ def _assert_no_mount_layers(self):
334
+ if self._mount_layers:
335
+ raise InvalidError(
336
+ "An image tried to run a build step after using `image.add_local_*` to include local files.\n"
337
+ "\n"
338
+ "Run `image.add_local_*` commands last in your image build to avoid rebuilding images with every local "
339
+ "file change. Modal will then add these files to containers on startup instead, saving build time.\n"
340
+ "If you need to run other build steps after adding local files, set `copy=True` to copy the files"
341
+ "directly into the image, at the expense of some added build time.\n"
342
+ "\n"
343
+ "Example:\n"
344
+ "\n"
345
+ "my_image = (\n"
346
+ " Image.debian_slim()\n"
347
+ ' .add_local_python_packages("mypak", copy=True)\n'
348
+ ' .run_commands("python -m mypak") # this now works!\n'
349
+ ")\n"
350
+ )
351
+
295
352
  @staticmethod
296
353
  def _from_args(
297
354
  *,
@@ -306,9 +363,11 @@ class _Image(_Object, type_prefix="im"):
306
363
  force_build: bool = False,
307
364
  # For internal use only.
308
365
  _namespace: int = api_pb2.DEPLOYMENT_NAMESPACE_WORKSPACE,
366
+ _do_assert_no_mount_layers: bool = True,
309
367
  ):
310
368
  if base_images is None:
311
369
  base_images = {}
370
+
312
371
  if secrets is None:
313
372
  secrets = []
314
373
  if gpu_config is None:
@@ -334,6 +393,11 @@ class _Image(_Object, type_prefix="im"):
334
393
  return deps
335
394
 
336
395
  async def _load(self: _Image, resolver: Resolver, existing_object_id: Optional[str]):
396
+ if _do_assert_no_mount_layers:
397
+ for image in base_images.values():
398
+ # base images can't have
399
+ image._assert_no_mount_layers()
400
+
337
401
  environment = await _get_environment_cached(resolver.environment_name or "", resolver.client)
338
402
  # A bit hacky,but assume that the environment provides a valid builder version
339
403
  image_builder_version = cast(ImageBuilderVersion, environment._settings.image_builder_version)
@@ -349,7 +413,9 @@ class _Image(_Object, type_prefix="im"):
349
413
  "No commands were provided for the image — have you tried using modal.Image.debian_slim()?"
350
414
  )
351
415
  if dockerfile.commands and build_function:
352
- raise InvalidError("Cannot provide both a build function and Dockerfile commands!")
416
+ raise InvalidError(
417
+ "Cannot provide both build function and Dockerfile commands in the same image layer!"
418
+ )
353
419
 
354
420
  base_images_pb2s = [
355
421
  api_pb2.BaseImage(
@@ -482,12 +548,12 @@ class _Image(_Object, type_prefix="im"):
482
548
  self._hydrate(image_id, resolver.client, result_response.metadata)
483
549
  local_mounts = set()
484
550
  for base in base_images.values():
485
- local_mounts |= base._used_local_mounts
551
+ local_mounts |= base._serve_mounts
486
552
  if context_mount and context_mount.is_local():
487
553
  local_mounts.add(context_mount)
488
- self._used_local_mounts = frozenset(local_mounts)
554
+ self._serve_mounts = frozenset(local_mounts)
489
555
 
490
- rep = "Image()"
556
+ rep = f"Image({dockerfile_function})"
491
557
  obj = _Image._from_loader(_load, rep, deps=_deps)
492
558
  obj.force_build = force_build
493
559
  return obj
@@ -553,6 +619,27 @@ class _Image(_Object, type_prefix="im"):
553
619
  context_mount=mount,
554
620
  )
555
621
 
622
+ def _add_local_python_packages(self, *packages: Union[str, Path], copy: bool = False) -> "_Image":
623
+ """Adds Python package files to containers
624
+
625
+ Adds all files from the specified Python packages to containers running the Image.
626
+
627
+ Packages are added to the `/root` directory of containers, which is on the `PYTHONPATH`
628
+ of any executed Modal Functions.
629
+
630
+ By default (`copy=False`), the files are added to containers on startup and are not built into the actual Image,
631
+ which speeds up deployment.
632
+
633
+ Set `copy=True` to copy the files into an Image layer at build time instead. This can slow down iteration since
634
+ it requires a rebuild of the Image and any subsequent build steps whenever the included files change, but it is
635
+ required if you want to run additional build steps after this one.
636
+
637
+ **Note:** This excludes all dot-prefixed subdirectories or files and all `.pyc`/`__pycache__` files.
638
+ To add full directories with finer control, use `.add_local_dir()` instead.
639
+ """
640
+ mount = _Mount.from_local_python_packages(*packages)
641
+ return self._add_mount_layer_or_copy(mount, copy=copy)
642
+
556
643
  def copy_local_dir(self, local_path: Union[str, Path], remote_path: Union[str, Path] = ".") -> "_Image":
557
644
  """Copy a directory into the image as a part of building the image.
558
645
 
modal/image.pyi CHANGED
@@ -58,11 +58,17 @@ class DockerfileSpec:
58
58
  class _Image(modal.object._Object):
59
59
  force_build: bool
60
60
  inside_exceptions: typing.List[Exception]
61
- _used_local_mounts: typing.FrozenSet[modal.mount._Mount]
61
+ _serve_mounts: typing.FrozenSet[modal.mount._Mount]
62
+ _deferred_mounts: typing.Sequence[modal.mount._Mount]
62
63
  _metadata: typing.Optional[modal_proto.api_pb2.ImageMetadata]
63
64
 
64
65
  def _initialize_from_empty(self): ...
66
+ def _initialize_from_other(self, other: _Image): ...
65
67
  def _hydrate_metadata(self, message: typing.Optional[google.protobuf.message.Message]): ...
68
+ def _add_mount_layer_or_copy(self, mount: modal.mount._Mount, copy: bool = False): ...
69
+ @property
70
+ def _mount_layers(self) -> typing.Tuple[modal.mount._Mount]: ...
71
+ def _assert_no_mount_layers(self): ...
66
72
  @staticmethod
67
73
  def _from_args(
68
74
  *,
@@ -78,6 +84,7 @@ class _Image(modal.object._Object):
78
84
  context_mount: typing.Optional[modal.mount._Mount] = None,
79
85
  force_build: bool = False,
80
86
  _namespace: int = 1,
87
+ _do_assert_no_mount_layers: bool = True,
81
88
  ): ...
82
89
  def extend(
83
90
  self,
@@ -90,11 +97,13 @@ class _Image(modal.object._Object):
90
97
  context_mount: typing.Optional[modal.mount._Mount] = None,
91
98
  force_build: bool = False,
92
99
  _namespace: int = 1,
100
+ _do_assert_no_mount_layers: bool = True,
93
101
  ) -> _Image: ...
94
102
  def copy_mount(self, mount: modal.mount._Mount, remote_path: typing.Union[str, pathlib.Path] = ".") -> _Image: ...
95
103
  def copy_local_file(
96
104
  self, local_path: typing.Union[str, pathlib.Path], remote_path: typing.Union[str, pathlib.Path] = "./"
97
105
  ) -> _Image: ...
106
+ def _add_local_python_packages(self, *module_names, copy: bool = False) -> _Image: ...
98
107
  def copy_local_dir(
99
108
  self, local_path: typing.Union[str, pathlib.Path], remote_path: typing.Union[str, pathlib.Path] = "."
100
109
  ) -> _Image: ...
@@ -299,12 +308,18 @@ class _Image(modal.object._Object):
299
308
  class Image(modal.object.Object):
300
309
  force_build: bool
301
310
  inside_exceptions: typing.List[Exception]
302
- _used_local_mounts: typing.FrozenSet[modal.mount.Mount]
311
+ _serve_mounts: typing.FrozenSet[modal.mount.Mount]
312
+ _deferred_mounts: typing.Sequence[modal.mount.Mount]
303
313
  _metadata: typing.Optional[modal_proto.api_pb2.ImageMetadata]
304
314
 
305
315
  def __init__(self, *args, **kwargs): ...
306
316
  def _initialize_from_empty(self): ...
317
+ def _initialize_from_other(self, other: Image): ...
307
318
  def _hydrate_metadata(self, message: typing.Optional[google.protobuf.message.Message]): ...
319
+ def _add_mount_layer_or_copy(self, mount: modal.mount.Mount, copy: bool = False): ...
320
+ @property
321
+ def _mount_layers(self) -> typing.Tuple[modal.mount.Mount]: ...
322
+ def _assert_no_mount_layers(self): ...
308
323
  @staticmethod
309
324
  def _from_args(
310
325
  *,
@@ -320,6 +335,7 @@ class Image(modal.object.Object):
320
335
  context_mount: typing.Optional[modal.mount.Mount] = None,
321
336
  force_build: bool = False,
322
337
  _namespace: int = 1,
338
+ _do_assert_no_mount_layers: bool = True,
323
339
  ): ...
324
340
  def extend(
325
341
  self,
@@ -332,11 +348,13 @@ class Image(modal.object.Object):
332
348
  context_mount: typing.Optional[modal.mount.Mount] = None,
333
349
  force_build: bool = False,
334
350
  _namespace: int = 1,
351
+ _do_assert_no_mount_layers: bool = True,
335
352
  ) -> Image: ...
336
353
  def copy_mount(self, mount: modal.mount.Mount, remote_path: typing.Union[str, pathlib.Path] = ".") -> Image: ...
337
354
  def copy_local_file(
338
355
  self, local_path: typing.Union[str, pathlib.Path], remote_path: typing.Union[str, pathlib.Path] = "./"
339
356
  ) -> Image: ...
357
+ def _add_local_python_packages(self, *module_names, copy: bool = False) -> Image: ...
340
358
  def copy_local_dir(
341
359
  self, local_path: typing.Union[str, pathlib.Path], remote_path: typing.Union[str, pathlib.Path] = "."
342
360
  ) -> Image: ...
modal/sandbox.py CHANGED
@@ -148,7 +148,7 @@ class _Sandbox(_Object, type_prefix="sb"):
148
148
  definition = api_pb2.Sandbox(
149
149
  entrypoint_args=entrypoint_args,
150
150
  image_id=image.object_id,
151
- mount_ids=[mount.object_id for mount in mounts],
151
+ mount_ids=[mount.object_id for mount in mounts] + [mount.object_id for mount in image._mount_layers],
152
152
  secret_ids=[secret.object_id for secret in secrets],
153
153
  timeout_secs=timeout,
154
154
  workdir=workdir,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: modal
3
- Version: 0.66.28
3
+ Version: 0.66.30
4
4
  Summary: Python client library for Modal
5
5
  Author: Modal Labs
6
6
  Author-email: support@modal.com
@@ -15,7 +15,6 @@ Requires-Python: >=3.9
15
15
  Description-Content-Type: text/markdown
16
16
  License-File: LICENSE
17
17
  Requires-Dist: aiohttp
18
- Requires-Dist: aiostream (~=0.5.2)
19
18
  Requires-Dist: certifi
20
19
  Requires-Dist: click (>=8.1.0)
21
20
  Requires-Dist: fastapi
@@ -15,11 +15,11 @@ modal/_traceback.py,sha256=1yNp1Dqq4qRIQp8idDp5PEqjwH4eA8MNI0FhFkCOFgo,4408
15
15
  modal/_tunnel.py,sha256=SVmQxGbV7dcLwyY9eB2PIWmXw8QQmcKg2ppTcRQgZrU,6283
16
16
  modal/_tunnel.pyi,sha256=SA_Q0UGB-D9skFjv6CqlTnCEWU67a2xJxfwVdXtar3Y,1259
17
17
  modal/_watcher.py,sha256=STlDe73R7IS33a_GMW2HnDc3hCDKLdsBfMxRpVh-flA,3581
18
- modal/app.py,sha256=_uBkLmXtx2scIg-ggcVcGoShVXV1jwm-xOSUgac1YAI,45858
18
+ modal/app.py,sha256=U_uQdjVnBBM8q3GkfMN90C6qW6gS_RwpqekXS-5ESII,45853
19
19
  modal/app.pyi,sha256=wHwBIDqkUb2CQzYVhxZafJ8xZ17TZ-8y-cRyOeZsEm0,25182
20
20
  modal/call_graph.py,sha256=l-Wi6vM8aosCdHTWegcCyGeVJGFdZ_fzlCmbRVPBXFI,2593
21
21
  modal/client.py,sha256=4SpWb4n0nolITR36kADZl1tYLOg6avukmzZU56UQjCo,16385
22
- modal/client.pyi,sha256=XYSPSjNI9rs-WTzBv0ULL4bD3bbYjp70E-OfC_IXHNM,7372
22
+ modal/client.pyi,sha256=8dNf-qkUmqE4iwwN3DzHgQgOH1NsjVUVdDoHtue1MRI,7372
23
23
  modal/cloud_bucket_mount.py,sha256=eWQhCtMIczpokjfTZEgNBCGO_s5ft46PqTSLfKBykq4,5748
24
24
  modal/cloud_bucket_mount.pyi,sha256=tTF7M4FR9bTA30cFkz8qq3ZTlFL19NHU_36e_5GgAGA,1424
25
25
  modal/cls.py,sha256=Ci7EtMrLm1LExfjZ9K2IXyj-SV9Syq8dAbZCEfddcmY,24234
@@ -33,11 +33,11 @@ modal/environments.py,sha256=KwKdrWfSnz2XF5eYXZyd0kdac1x1PVw2uxPYsGy8cys,6517
33
33
  modal/environments.pyi,sha256=oScvFAclF55-tL9UioLIL_SPBwgy_9O-BBvJ-PLbRgY,3542
34
34
  modal/exception.py,sha256=K-czk1oK8wFvK8snWrytXSByo2WNb9SJAlgBVPGWZBs,6417
35
35
  modal/experimental.py,sha256=jFuNbwrNHos47viMB9q-cHJSvf2RDxDdoEcss9plaZE,2302
36
- modal/functions.py,sha256=5eSi8UpJTHCXmoRGzKqTMIj3VDTHL7q_Wfc8NQhsppA,71694
37
- modal/functions.pyi,sha256=NNQ99RPpP9orbwigl5BaXWJtcvl6sEyjFapzCT3mjkY,24949
36
+ modal/functions.py,sha256=3iAonXDZ1OXgtUhL1LuTguNxlJi_PtGu-cBibd6Y464,71837
37
+ modal/functions.pyi,sha256=cvEhksXdIvBkEj2U3TDeOGUYqKYCaAL8f2ryO_LUkl8,24939
38
38
  modal/gpu.py,sha256=r4rL6uH3UJIQthzYvfWauXNyh01WqCPtKZCmmSX1fd4,6881
39
- modal/image.py,sha256=40iKoSUrKtar1tT689zF1QuVaIcMmLsoU7rr1NCQbQ4,71798
40
- modal/image.pyi,sha256=tjZeFHmLP9bsX8rINg0dYZ8tz-xpFr5z04Wt0GRwc0E,22820
39
+ modal/image.py,sha256=E6UVnhOdfkMnajiSpIm0iUEyE04yclkv9Y0BO6Vplrg,76043
40
+ modal/image.pyi,sha256=ZQpSN7XR16aug50sEcDE597CPssekeP1UZBtq0F1lRk,23847
41
41
  modal/io_streams.py,sha256=kZ5o-aK0lPg4-NezYxpCFmjS2Vf_TbWn49S7c2xUQ6U,14255
42
42
  modal/io_streams.pyi,sha256=pn6UnOjCUjQwukPYiHHdCv92CH9S9YRb_WekKGoPN94,4350
43
43
  modal/mount.py,sha256=kWEz3yFdoVa0XFp3SA9HfaH7kSO7K_mMNHnm_e3tbDo,27616
@@ -60,7 +60,7 @@ modal/retries.py,sha256=z4dYXdksUcjkefM3vGLkhCQ_m_TUPLJgC4uSYDzWSOU,3750
60
60
  modal/runner.py,sha256=ZHHuPQ130pZzHdm8vOVQx6db4FiEg3SheDNyShVn9Jg,23805
61
61
  modal/runner.pyi,sha256=b2qoID4HO-ww6Q0jdboR9iCTxVWTzGiC2taIx7kA-U0,5135
62
62
  modal/running_app.py,sha256=AhWWCB16_k5R80oQxEVSNrmRq3fVInUCxtXKrAvcEPQ,566
63
- modal/sandbox.py,sha256=DL-UW4AJOJPm9Wqm5LDBSNjpREOc-DxHkdgp-68HIk0,24825
63
+ modal/sandbox.py,sha256=_7_sqTrEiC2zFo1XN7UCHA1L9NFXj6Kb6xu6Ecfancg,24878
64
64
  modal/sandbox.pyi,sha256=LIh3cIs9Wm0x2WBpyLqmlOvqJYB2806sO4JCIJRQOi4,17231
65
65
  modal/schedule.py,sha256=0ZFpKs1bOxeo5n3HZjoL7OE2ktsb-_oGtq-WJEPO4tY,2615
66
66
  modal/scheduler_placement.py,sha256=2B7CAR4UMUu5AtFVWgwVFDjkKtppwKY6ek7gD0jzBYI,1208
@@ -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=UnAuHBPuPSstqgdCOx0SBVdfhpeJnMlY_oxEbu44Izg,470
161
161
  modal_version/__main__.py,sha256=2FO0yYQQwDTh6udt1h-cBnGd1c4ZyHnHSI4BksxzVac,105
162
- modal_version/_version_generated.py,sha256=SCAqoQe_ZnDBoZO8foXDdhS9i7esaprMTiXo_gFcUzo,149
163
- modal-0.66.28.dist-info/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
164
- modal-0.66.28.dist-info/METADATA,sha256=v6hC_QXntdS-kwAoX4Ti_5BsejSSCKcBMpV1TqwFGYk,2364
165
- modal-0.66.28.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
166
- modal-0.66.28.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
167
- modal-0.66.28.dist-info/top_level.txt,sha256=1nvYbOSIKcmU50fNrpnQnrrOpj269ei3LzgB6j9xGqg,64
168
- modal-0.66.28.dist-info/RECORD,,
162
+ modal_version/_version_generated.py,sha256=im-FFVUnQj3OsyaPwp-GZ1ylzEKwyPjLnswUY4O1WjA,149
163
+ modal-0.66.30.dist-info/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
164
+ modal-0.66.30.dist-info/METADATA,sha256=T45kCxJAkuhDkfwbYWCEWtZSTBNKoc-K5-4ec2v2ncI,2329
165
+ modal-0.66.30.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
166
+ modal-0.66.30.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
167
+ modal-0.66.30.dist-info/top_level.txt,sha256=1nvYbOSIKcmU50fNrpnQnrrOpj269ei3LzgB6j9xGqg,64
168
+ modal-0.66.30.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  # Copyright Modal Labs 2024
2
2
 
3
3
  # Note: Reset this value to -1 whenever you make a minor `0.X` release of the client.
4
- build_number = 28 # git: 4758f34
4
+ build_number = 30 # git: 734d82d