modal 0.66.23__py3-none-any.whl → 0.66.35__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.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]
@@ -450,11 +450,11 @@ class Function(typing.Generic[P, ReturnType, OriginalReturnType], modal.object.O
450
450
 
451
451
  _call_generator_nowait: ___call_generator_nowait_spec
452
452
 
453
- class __remote_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER]):
453
+ class __remote_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER]):
454
454
  def __call__(self, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> ReturnType_INNER: ...
455
455
  async def aio(self, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> ReturnType_INNER: ...
456
456
 
457
- remote: __remote_spec[ReturnType, P]
457
+ remote: __remote_spec[P, ReturnType]
458
458
 
459
459
  class __remote_gen_spec(typing_extensions.Protocol):
460
460
  def __call__(self, *args, **kwargs) -> typing.Generator[typing.Any, None, None]: ...
@@ -466,17 +466,17 @@ class Function(typing.Generic[P, ReturnType, OriginalReturnType], modal.object.O
466
466
  def _get_obj(self) -> typing.Optional[modal.cls.Obj]: ...
467
467
  def local(self, *args: P.args, **kwargs: P.kwargs) -> OriginalReturnType: ...
468
468
 
469
- class ___experimental_spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER]):
469
+ class ___experimental_spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER]):
470
470
  def __call__(self, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]: ...
471
471
  async def aio(self, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]: ...
472
472
 
473
- _experimental_spawn: ___experimental_spawn_spec[ReturnType, P]
473
+ _experimental_spawn: ___experimental_spawn_spec[P, ReturnType]
474
474
 
475
- class __spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER]):
475
+ class __spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER]):
476
476
  def __call__(self, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]: ...
477
477
  async def aio(self, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]: ...
478
478
 
479
- spawn: __spawn_spec[ReturnType, P]
479
+ spawn: __spawn_spec[P, ReturnType]
480
480
 
481
481
  def get_raw_f(self) -> typing.Callable[..., typing.Any]: ...
482
482
 
modal/gpu.py CHANGED
@@ -161,7 +161,7 @@ __doc__ = f"""
161
161
  **GPU configuration shortcodes**
162
162
 
163
163
  The following are the valid `str` values for the `gpu` parameter of
164
- [`@app.function`](/docs/reference/modal.Stub#function).
164
+ [`@app.function`](/docs/reference/modal.App#function).
165
165
 
166
166
  {display_string_to_config}
167
167
 
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/partial_function.py CHANGED
@@ -379,6 +379,11 @@ def _asgi_app(
379
379
  f"Modal will drop support for default parameters in a future release.",
380
380
  )
381
381
 
382
+ if inspect.iscoroutinefunction(raw_f):
383
+ raise InvalidError(
384
+ f"ASGI app function {raw_f.__name__} is an async function. Only sync Python functions are supported."
385
+ )
386
+
382
387
  if not wait_for_response:
383
388
  deprecation_error(
384
389
  (2024, 5, 13),
@@ -448,6 +453,11 @@ def _wsgi_app(
448
453
  f"Modal will drop support for default parameters in a future release.",
449
454
  )
450
455
 
456
+ if inspect.iscoroutinefunction(raw_f):
457
+ raise InvalidError(
458
+ f"WSGI app function {raw_f.__name__} is an async function. Only sync Python functions are supported."
459
+ )
460
+
451
461
  if not wait_for_response:
452
462
  deprecation_error(
453
463
  (2024, 5, 13),
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.23
3
+ Version: 0.66.35
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
@@ -2,7 +2,7 @@ modal/__init__.py,sha256=Yn8zS7Jxl5uZjPM331Pc4FdSmp9Rt6VdE7TiE4ZKRc8,2151
2
2
  modal/__main__.py,sha256=scYhGFqh8OJcVDo-VOxIT6CCwxOgzgflYWMnIZiMRqE,2871
3
3
  modal/_clustered_functions.py,sha256=58spAmCbOk8eyjFKW-H21W-FGyYiJmfpEMK4BnTEUrk,2706
4
4
  modal/_clustered_functions.pyi,sha256=UQ7DHiQFI3A2Z8kC3gltNHJkQfvgvPuSbFsse9lSPkw,785
5
- modal/_container_entrypoint.py,sha256=HLr7F4aOnpyBpAAxAaxZC664pflQn2lbssyXYfUvc7I,42099
5
+ modal/_container_entrypoint.py,sha256=T0Ql-oxgmj7PRVtdF4wYEGq-_a1ZACuCxe6u2XYj0nk,28671
6
6
  modal/_ipython.py,sha256=HF_DYy0e0qM9WnGDmTY30s1RxzGya9GeORCauCEpRaE,450
7
7
  modal/_location.py,sha256=S3lSxIU3h9HkWpkJ3Pwo0pqjIOSB1fjeSgUsY3x7eec,1202
8
8
  modal/_output.py,sha256=SMaLrf1btBzHTV_tH5NzA8ZTWNJh5J0b31iG3sQU8_4,25494
@@ -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=sECTGUkkQceBdaaJG2TW3TKSyRQjxZL4UFBrJcgew9I,45869
18
+ modal/app.py,sha256=QEBK8qYSrux36oi3iS3msBQmcUOS1r4s2nengzzynjQ,44658
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=rAHr-CRw4ke5RuVxRRjma_lClLWWJsyYojRtJX95T68,7372
22
+ modal/client.pyi,sha256=O-F0HqNcgFP5bMrCEmgjBrmZs4yH-A6s9eQTNMxCIf8,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
@@ -32,12 +32,12 @@ modal/dict.pyi,sha256=4Rh5HNzXk99hotPUzoj1kYOHNlEgndZFfA-hlmBtBIc,7223
32
32
  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
- modal/experimental.py,sha256=lN6Zj18XxXCxZu2JNI3vdaehIqXQYlhv3UvR5h97jD4,2305
36
- modal/functions.py,sha256=5QxkWLewiwa9Q88QM036V1cBvF9d0ij6d_kz7WGmJ8g,71717
37
- modal/functions.pyi,sha256=5Tsh8Di9HtnpZ3aySnBLdLBRRu99NZ6moBsNJoo7rCs,24949
38
- modal/gpu.py,sha256=93NGhGSP920c6IvS_ULyUWKm4-I3fWuqxkOd2ccANDk,6882
39
- modal/image.py,sha256=40iKoSUrKtar1tT689zF1QuVaIcMmLsoU7rr1NCQbQ4,71798
40
- modal/image.pyi,sha256=tjZeFHmLP9bsX8rINg0dYZ8tz-xpFr5z04Wt0GRwc0E,22820
35
+ modal/experimental.py,sha256=jFuNbwrNHos47viMB9q-cHJSvf2RDxDdoEcss9plaZE,2302
36
+ modal/functions.py,sha256=3iAonXDZ1OXgtUhL1LuTguNxlJi_PtGu-cBibd6Y464,71837
37
+ modal/functions.pyi,sha256=cvEhksXdIvBkEj2U3TDeOGUYqKYCaAL8f2ryO_LUkl8,24939
38
+ modal/gpu.py,sha256=r4rL6uH3UJIQthzYvfWauXNyh01WqCPtKZCmmSX1fd4,6881
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
@@ -49,7 +49,7 @@ modal/object.pyi,sha256=cwWg93H4rBk9evt1itLZAZXH5wUMyTJBZ_ADazgfjGg,8465
49
49
  modal/output.py,sha256=FtPR7yvjZMgdSKD_KYkIcwYgCOiV9EKYjaj7K55Hjvg,1940
50
50
  modal/parallel_map.py,sha256=lf8Wer6FAf8-dYqPqoL45cz7FYDU66-TF-h5CO2Kf5Q,16052
51
51
  modal/parallel_map.pyi,sha256=pOhT0P3DDYlwLx0fR3PTsecA7DI8uOdXC1N8i-ZkyOY,2328
52
- modal/partial_function.py,sha256=RNsdmgmQgE_lxDJPvtu6KgbF0NhxWMvwU4FLCiKIdG8,27786
52
+ modal/partial_function.py,sha256=hCu7-kfNl_g-dvfx2VW1GyJqJ3zAgEnEqDEXUfQPO6I,28210
53
53
  modal/partial_function.pyi,sha256=BqKN7It5QLxS2yhhhDX0RgI8EyNMPBD6Duk21kN_fvA,8908
54
54
  modal/proxy.py,sha256=ZrOsuQP7dSZFq1OrIxalNnt0Zvsnp1h86Th679sSL40,1417
55
55
  modal/proxy.pyi,sha256=UvygdOYneLTuoDY6hVaMNCyZ947Tmx93IdLjErUqkvM,368
@@ -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
@@ -75,9 +75,10 @@ modal/volume.py,sha256=PfwXajTBuZdxwQv2lHRqzfchn39I77pRiC60Ga1EJo4,28914
75
75
  modal/volume.pyi,sha256=JbeGYBda2mctzyK2psAen4nnfFB2v3jEB7S7Oyv_Vm0,10986
76
76
  modal/_runtime/__init__.py,sha256=MIEP8jhXUeGq_eCjYFcqN5b1bxBM4fdk0VESpjWR0fc,28
77
77
  modal/_runtime/asgi.py,sha256=WoAwIiGKpk089MOca3_iA73h36v0uBuoPx0-87ajIDY,19843
78
- modal/_runtime/container_io_manager.py,sha256=FesoR2WVEdGhZgOo5XXldCznGNt5krc-ht1IxyANCCY,44202
78
+ modal/_runtime/container_io_manager.py,sha256=_MEhwyCSYeCaPQnztPxkm0anRXa3CPcwIKi403N53uo,44120
79
79
  modal/_runtime/execution_context.py,sha256=cXEVY4wEK-oZJVJptyj1ZplZvVQ1HDzFsyHxhaY4o8M,2718
80
80
  modal/_runtime/telemetry.py,sha256=3NbrfwYH6mvDckzdTppymmda2lQKX2oHGc2JwdFZdUc,5191
81
+ modal/_runtime/user_code_imports.py,sha256=R06r4e5Dwmes0bgmHClotBN_vd5Etss8Ml4vVtfW8wI,14542
81
82
  modal/_utils/__init__.py,sha256=waLjl5c6IPDhSsdWAm9Bji4e2PVxamYABKAze6CHVXY,28
82
83
  modal/_utils/app_utils.py,sha256=88BT4TPLWfYAQwKTHcyzNQRHg8n9B-QE2UyJs96iV-0,108
83
84
  modal/_utils/async_utils.py,sha256=3H4pBC4DW6rCA6hgRux6FMxGqPgHM-G-BTs7KXZiWz4,23958
@@ -107,7 +108,7 @@ modal/cli/container.py,sha256=LGrF9iz8D3PGst6IUl0VB1Y1LJ0BWLrNRNFxWa4z-tg,3199
107
108
  modal/cli/dict.py,sha256=lIEl6uxygFt3omC-oF6tHUxnFjVhy4d0InC_kZrlkvM,4454
108
109
  modal/cli/entry_point.py,sha256=aaNxFAqZcmtSjwzkYIA_Ba9CkL4cL4_i2gy5VjoXxkM,4228
109
110
  modal/cli/environment.py,sha256=eq8Rixbo8u-nJPvtGwW4-I1lXZPnevsFEv65WlSxFXY,4362
110
- modal/cli/import_refs.py,sha256=Qk5jrX4ffrJZbT4H1I1y0jXkqfMLZ1pJhpyY6d5DihE,10616
111
+ modal/cli/import_refs.py,sha256=0sYZLcgcnor_CECq-7yX3WBs1W55nz5y65sbysxxKzY,9267
111
112
  modal/cli/launch.py,sha256=aY1fXxZyGn1Ih0lAzuAvzpXP6_OxvVCoZCgCIyV9Vos,2692
112
113
  modal/cli/network_file_system.py,sha256=p_o3wu8rh2tjHXJYrjaad__pD8hv93ypeDtfSY2fSEU,7527
113
114
  modal/cli/profile.py,sha256=s4jCYHwriOorEFCKxeGZoSWX8rXTR_hDTNFZhOA565s,3109
@@ -141,10 +142,10 @@ modal_global_objects/mounts/__init__.py,sha256=MIEP8jhXUeGq_eCjYFcqN5b1bxBM4fdk0
141
142
  modal_global_objects/mounts/modal_client_package.py,sha256=W0E_yShsRojPzWm6LtIQqNVolapdnrZkm2hVEQuZK_4,767
142
143
  modal_global_objects/mounts/python_standalone.py,sha256=_vTEX3PECUsatzhDs8lyJmDK0LbFetT1sJB6MIDfFAo,1870
143
144
  modal_proto/__init__.py,sha256=MIEP8jhXUeGq_eCjYFcqN5b1bxBM4fdk0VESpjWR0fc,28
144
- modal_proto/api.proto,sha256=FGmfdyUxMgxbxo1m5qkJVqDESidd6VGNvswfZ5xMA4k,77300
145
+ modal_proto/api.proto,sha256=5MPLgs49i-i_BcP19GyOUJ7hcpWuoegTKkjXJG0Eujg,77352
145
146
  modal_proto/api_grpc.py,sha256=S7h8xe-msb3-Q8oSd7DUoB46z-dcRhsXGb6LjFCLNFI,99013
146
- modal_proto/api_pb2.py,sha256=sfMWbd1ELWTcdZiJyUzJrwYNHxLtb84zFS19Bg2VVmc,282645
147
- modal_proto/api_pb2.pyi,sha256=Fj65ydXEBbGMNPDPRmt9G7CBGKpujYppB0D8gwcW3cQ,377389
147
+ modal_proto/api_pb2.py,sha256=I8lNXEGFRHCPfpozfs2-7aVIG9edTokoJYv-wjYcmpg,282733
148
+ modal_proto/api_pb2.pyi,sha256=q6T8rJYt-V4UQ_Dr8xuqUMwJCMjs-iC1rHhycZrHUpo,377728
148
149
  modal_proto/api_pb2_grpc.py,sha256=g7EfCSir3xStPPjJOU2U668zz6cGdN6u7SxvTTwU9aU,214126
149
150
  modal_proto/api_pb2_grpc.pyi,sha256=9GhLZVRm69Qhyj_jmGqEGv1rD37Tzj6E6hGzKV08u48,49961
150
151
  modal_proto/modal_api_grpc.py,sha256=en48QTR5fwA7x0twtlsqLKRjjDEAKVoh6EeSznQfQ3U,13236
@@ -158,10 +159,10 @@ modal_proto/options_pb2_grpc.pyi,sha256=CImmhxHsYnF09iENPoe8S4J-n93jtgUYD2JPAc0y
158
159
  modal_proto/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
159
160
  modal_version/__init__.py,sha256=UnAuHBPuPSstqgdCOx0SBVdfhpeJnMlY_oxEbu44Izg,470
160
161
  modal_version/__main__.py,sha256=2FO0yYQQwDTh6udt1h-cBnGd1c4ZyHnHSI4BksxzVac,105
161
- modal_version/_version_generated.py,sha256=PEJZxsXHps9h6IOTa8SVD4r_V8h5EHoHOvbunwRqnDk,149
162
- modal-0.66.23.dist-info/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
163
- modal-0.66.23.dist-info/METADATA,sha256=JlKzno-zvMvg622e--jMcVq2kN__xGfOXfMTYBRybRo,2364
164
- modal-0.66.23.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
165
- modal-0.66.23.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
166
- modal-0.66.23.dist-info/top_level.txt,sha256=1nvYbOSIKcmU50fNrpnQnrrOpj269ei3LzgB6j9xGqg,64
167
- modal-0.66.23.dist-info/RECORD,,
162
+ modal_version/_version_generated.py,sha256=eRGQyWJtzjEtN61stKVibxiwRPyBco_QTdotS1XLXCw,149
163
+ modal-0.66.35.dist-info/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
164
+ modal-0.66.35.dist-info/METADATA,sha256=GX8ZnQh-2qTATASTZTCoF1T18y0CP0WhOfxfrrwYCOo,2329
165
+ modal-0.66.35.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
166
+ modal-0.66.35.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
167
+ modal-0.66.35.dist-info/top_level.txt,sha256=1nvYbOSIKcmU50fNrpnQnrrOpj269ei3LzgB6j9xGqg,64
168
+ modal-0.66.35.dist-info/RECORD,,
modal_proto/api.proto CHANGED
@@ -1754,6 +1754,7 @@ message MethodDefinition {
1754
1754
  WebhookConfig webhook_config = 3;
1755
1755
  string web_url = 4;
1756
1756
  WebUrlInfo web_url_info = 5;
1757
+ repeated CustomDomainInfo custom_domain_info = 6;
1757
1758
  }
1758
1759
 
1759
1760
  message MountFile {