modal 1.2.2.dev30__py3-none-any.whl → 1.2.2.dev36__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 +77 -52
- modal/_load_context.py +105 -0
- modal/_object.py +47 -18
- modal/_resolver.py +21 -35
- modal/app.py +7 -0
- modal/app.pyi +3 -0
- modal/cli/dict.py +5 -2
- modal/cli/queues.py +4 -2
- modal/client.pyi +2 -2
- modal/cls.py +71 -32
- modal/cls.pyi +3 -0
- modal/dict.py +14 -5
- modal/dict.pyi +2 -0
- modal/environments.py +16 -7
- modal/environments.pyi +6 -2
- modal/functions.pyi +10 -4
- modal/image.py +22 -22
- modal/mount.py +35 -25
- modal/mount.pyi +33 -7
- modal/network_file_system.py +14 -5
- modal/network_file_system.pyi +12 -2
- modal/object.pyi +35 -8
- modal/proxy.py +14 -6
- modal/proxy.pyi +10 -2
- modal/queue.py +14 -5
- modal/queue.pyi +12 -2
- modal/runner.py +43 -47
- modal/runner.pyi +2 -2
- modal/sandbox.py +21 -12
- modal/secret.py +57 -39
- modal/secret.pyi +21 -4
- modal/serving.py +7 -11
- modal/serving.pyi +7 -8
- modal/snapshot.py +11 -5
- modal/volume.py +25 -7
- modal/volume.pyi +2 -0
- {modal-1.2.2.dev30.dist-info → modal-1.2.2.dev36.dist-info}/METADATA +1 -1
- {modal-1.2.2.dev30.dist-info → modal-1.2.2.dev36.dist-info}/RECORD +46 -45
- modal_proto/api.proto +4 -0
- modal_proto/api_pb2.py +684 -684
- modal_proto/api_pb2.pyi +24 -3
- modal_version/__init__.py +1 -1
- {modal-1.2.2.dev30.dist-info → modal-1.2.2.dev36.dist-info}/WHEEL +0 -0
- {modal-1.2.2.dev30.dist-info → modal-1.2.2.dev36.dist-info}/entry_points.txt +0 -0
- {modal-1.2.2.dev30.dist-info → modal-1.2.2.dev36.dist-info}/licenses/LICENSE +0 -0
- {modal-1.2.2.dev30.dist-info → modal-1.2.2.dev36.dist-info}/top_level.txt +0 -0
modal/image.py
CHANGED
|
@@ -28,6 +28,7 @@ from typing_extensions import Self
|
|
|
28
28
|
from modal._serialization import serialize_data_format
|
|
29
29
|
from modal_proto import api_pb2
|
|
30
30
|
|
|
31
|
+
from ._load_context import LoadContext
|
|
31
32
|
from ._object import _Object, live_method_gen
|
|
32
33
|
from ._resolver import Resolver
|
|
33
34
|
from ._serialization import get_preferred_payload_format, serialize
|
|
@@ -434,12 +435,16 @@ class _Image(_Object, type_prefix="im"):
|
|
|
434
435
|
|
|
435
436
|
base_image = self
|
|
436
437
|
|
|
437
|
-
async def _load(
|
|
438
|
+
async def _load(
|
|
439
|
+
self2: "_Image", resolver: Resolver, load_context: LoadContext, existing_object_id: Optional[str]
|
|
440
|
+
):
|
|
438
441
|
self2._hydrate_from_other(base_image) # same image id as base image as long as it's lazy
|
|
439
442
|
self2._deferred_mounts = tuple(base_image._deferred_mounts) + (mount,)
|
|
440
443
|
self2._serve_mounts = base_image._serve_mounts | ({mount} if mount.is_local() else set())
|
|
441
444
|
|
|
442
|
-
img = _Image._from_loader(
|
|
445
|
+
img = _Image._from_loader(
|
|
446
|
+
_load, "Image(local files)", deps=lambda: [base_image, mount], load_context_overrides=LoadContext.empty()
|
|
447
|
+
)
|
|
443
448
|
img._added_python_source_set = base_image._added_python_source_set
|
|
444
449
|
return img
|
|
445
450
|
|
|
@@ -523,18 +528,18 @@ class _Image(_Object, type_prefix="im"):
|
|
|
523
528
|
deps += (vol,)
|
|
524
529
|
return deps
|
|
525
530
|
|
|
526
|
-
async def _load(self: _Image, resolver: Resolver, existing_object_id: Optional[str]):
|
|
531
|
+
async def _load(self: _Image, resolver: Resolver, load_context: LoadContext, existing_object_id: Optional[str]):
|
|
527
532
|
context_mount = context_mount_function() if context_mount_function else None
|
|
528
533
|
if context_mount:
|
|
529
|
-
await resolver.load(context_mount)
|
|
534
|
+
await resolver.load(context_mount, load_context)
|
|
530
535
|
|
|
531
536
|
if _do_assert_no_mount_layers:
|
|
532
537
|
for image in base_images.values():
|
|
533
538
|
# base images can't have
|
|
534
539
|
image._assert_no_mount_layers()
|
|
535
540
|
|
|
536
|
-
assert
|
|
537
|
-
environment = await _get_environment_cached(
|
|
541
|
+
assert load_context.app_id # type narrowing
|
|
542
|
+
environment = await _get_environment_cached(load_context.environment_name or "", load_context.client)
|
|
538
543
|
# A bit hacky,but assume that the environment provides a valid builder version
|
|
539
544
|
image_builder_version = cast(ImageBuilderVersion, environment._settings.image_builder_version)
|
|
540
545
|
builder_version = _get_image_builder_version(image_builder_version)
|
|
@@ -626,7 +631,7 @@ class _Image(_Object, type_prefix="im"):
|
|
|
626
631
|
)
|
|
627
632
|
|
|
628
633
|
req = api_pb2.ImageGetOrCreateRequest(
|
|
629
|
-
app_id=
|
|
634
|
+
app_id=load_context.app_id,
|
|
630
635
|
image=image_definition,
|
|
631
636
|
existing_image_id=existing_object_id or "", # TODO: ignored
|
|
632
637
|
build_function_id=build_function_id,
|
|
@@ -638,7 +643,7 @@ class _Image(_Object, type_prefix="im"):
|
|
|
638
643
|
allow_global_deployment=os.environ.get("MODAL_IMAGE_ALLOW_GLOBAL_DEPLOYMENT") == "1",
|
|
639
644
|
ignore_cache=config.get("ignore_cache"),
|
|
640
645
|
)
|
|
641
|
-
resp = await
|
|
646
|
+
resp = await load_context.client.stub.ImageGetOrCreate(req)
|
|
642
647
|
image_id = resp.image_id
|
|
643
648
|
result: api_pb2.GenericResult
|
|
644
649
|
metadata: Optional[api_pb2.ImageMetadata] = None
|
|
@@ -651,7 +656,7 @@ class _Image(_Object, type_prefix="im"):
|
|
|
651
656
|
else:
|
|
652
657
|
# not built or in the process of building - wait for build
|
|
653
658
|
logger.debug("Waiting for image %s" % image_id)
|
|
654
|
-
resp = await _image_await_build_result(image_id,
|
|
659
|
+
resp = await _image_await_build_result(image_id, load_context.client)
|
|
655
660
|
result = resp.result
|
|
656
661
|
if resp.HasField("metadata"):
|
|
657
662
|
metadata = resp.metadata
|
|
@@ -681,7 +686,7 @@ class _Image(_Object, type_prefix="im"):
|
|
|
681
686
|
else:
|
|
682
687
|
raise RemoteError("Unknown status %s!" % result.status)
|
|
683
688
|
|
|
684
|
-
self._hydrate(image_id,
|
|
689
|
+
self._hydrate(image_id, load_context.client, metadata)
|
|
685
690
|
local_mounts = set()
|
|
686
691
|
for base in base_images.values():
|
|
687
692
|
local_mounts |= base._serve_mounts
|
|
@@ -690,7 +695,7 @@ class _Image(_Object, type_prefix="im"):
|
|
|
690
695
|
self._serve_mounts = frozenset(local_mounts)
|
|
691
696
|
|
|
692
697
|
rep = f"Image({dockerfile_function})"
|
|
693
|
-
obj = _Image._from_loader(_load, rep, deps=_deps)
|
|
698
|
+
obj = _Image._from_loader(_load, rep, deps=_deps, load_context_overrides=LoadContext.empty())
|
|
694
699
|
obj.force_build = force_build
|
|
695
700
|
obj._added_python_source_set = frozenset.union(
|
|
696
701
|
frozenset(), *(base._added_python_source_set for base in base_images.values())
|
|
@@ -863,15 +868,13 @@ class _Image(_Object, type_prefix="im"):
|
|
|
863
868
|
|
|
864
869
|
The ID of an Image object can be accessed using `.object_id`.
|
|
865
870
|
"""
|
|
866
|
-
if client is None:
|
|
867
|
-
client = await _Client.from_env()
|
|
868
871
|
|
|
869
|
-
async def _load(self: _Image, resolver: Resolver, existing_object_id: Optional[str]):
|
|
870
|
-
resp = await client.stub.ImageFromId(api_pb2.ImageFromIdRequest(image_id=image_id))
|
|
871
|
-
self._hydrate(resp.image_id,
|
|
872
|
+
async def _load(self: _Image, resolver: Resolver, load_context: LoadContext, existing_object_id: Optional[str]):
|
|
873
|
+
resp = await load_context.client.stub.ImageFromId(api_pb2.ImageFromIdRequest(image_id=image_id))
|
|
874
|
+
self._hydrate(resp.image_id, load_context.client, resp.metadata)
|
|
872
875
|
|
|
873
876
|
rep = f"Image.from_id({image_id!r})"
|
|
874
|
-
obj = _Image._from_loader(_load, rep)
|
|
877
|
+
obj = _Image._from_loader(_load, rep, load_context_overrides=LoadContext(client=client))
|
|
875
878
|
|
|
876
879
|
return obj
|
|
877
880
|
|
|
@@ -930,11 +933,8 @@ class _Image(_Object, type_prefix="im"):
|
|
|
930
933
|
if app.app_id is None:
|
|
931
934
|
raise InvalidError("App has not been initialized yet. Use the content manager `app.run()` or `App.lookup`")
|
|
932
935
|
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
resolver = Resolver(app_client, app_id=app_id)
|
|
937
|
-
await resolver.load(self)
|
|
936
|
+
resolver = Resolver()
|
|
937
|
+
await resolver.load(self, app._root_load_context)
|
|
938
938
|
return self
|
|
939
939
|
|
|
940
940
|
def pip_install(
|
modal/mount.py
CHANGED
|
@@ -20,7 +20,8 @@ import modal.file_pattern_matcher
|
|
|
20
20
|
from modal_proto import api_pb2
|
|
21
21
|
from modal_version import __version__
|
|
22
22
|
|
|
23
|
-
from .
|
|
23
|
+
from ._load_context import LoadContext
|
|
24
|
+
from ._object import _Object
|
|
24
25
|
from ._resolver import Resolver
|
|
25
26
|
from ._utils.async_utils import TaskContext, aclosing, async_map, synchronize_api
|
|
26
27
|
from ._utils.blob_utils import FileUploadSpec, blob_upload_file, get_file_upload_spec_from_path
|
|
@@ -310,7 +311,7 @@ class _Mount(_Object, type_prefix="mo"):
|
|
|
310
311
|
_entries: Optional[list[_MountEntry]] = None
|
|
311
312
|
_deployment_name: Optional[str] = None
|
|
312
313
|
_namespace: Optional[int] = None
|
|
313
|
-
|
|
314
|
+
|
|
314
315
|
_allow_overwrite: bool = False
|
|
315
316
|
_content_checksum_sha256_hex: Optional[str] = None
|
|
316
317
|
|
|
@@ -325,7 +326,12 @@ class _Mount(_Object, type_prefix="mo"):
|
|
|
325
326
|
return None
|
|
326
327
|
return (_Mount._type_prefix, "local", frozenset(included_files))
|
|
327
328
|
|
|
328
|
-
obj = _Mount._from_loader(
|
|
329
|
+
obj = _Mount._from_loader(
|
|
330
|
+
_Mount._load_mount,
|
|
331
|
+
rep,
|
|
332
|
+
deduplication_key=mount_content_deduplication_key,
|
|
333
|
+
load_context_overrides=LoadContext.empty(),
|
|
334
|
+
)
|
|
329
335
|
obj._entries = entries
|
|
330
336
|
obj._is_local = True
|
|
331
337
|
return obj
|
|
@@ -477,6 +483,7 @@ class _Mount(_Object, type_prefix="mo"):
|
|
|
477
483
|
async def _load_mount(
|
|
478
484
|
self: "_Mount",
|
|
479
485
|
resolver: Resolver,
|
|
486
|
+
load_context: LoadContext,
|
|
480
487
|
existing_object_id: Optional[str],
|
|
481
488
|
):
|
|
482
489
|
t0 = time.monotonic()
|
|
@@ -518,7 +525,7 @@ class _Mount(_Object, type_prefix="mo"):
|
|
|
518
525
|
|
|
519
526
|
request = api_pb2.MountPutFileRequest(sha256_hex=file_spec.sha256_hex)
|
|
520
527
|
accounted_hashes.add(file_spec.sha256_hex)
|
|
521
|
-
response = await
|
|
528
|
+
response = await load_context.client.stub.MountPutFile(request, retry=Retry(base_delay=1))
|
|
522
529
|
|
|
523
530
|
if response.exists:
|
|
524
531
|
n_finished += 1
|
|
@@ -532,7 +539,7 @@ class _Mount(_Object, type_prefix="mo"):
|
|
|
532
539
|
async with blob_upload_concurrency:
|
|
533
540
|
with file_spec.source() as fp:
|
|
534
541
|
blob_id = await blob_upload_file(
|
|
535
|
-
fp,
|
|
542
|
+
fp, load_context.client.stub, sha256_hex=file_spec.sha256_hex, md5_hex=file_spec.md5_hex
|
|
536
543
|
)
|
|
537
544
|
logger.debug(f"Uploading blob file {file_spec.source_description} as {remote_filename}")
|
|
538
545
|
request2 = api_pb2.MountPutFileRequest(data_blob_id=blob_id, sha256_hex=file_spec.sha256_hex)
|
|
@@ -544,7 +551,7 @@ class _Mount(_Object, type_prefix="mo"):
|
|
|
544
551
|
|
|
545
552
|
start_time = time.monotonic()
|
|
546
553
|
while time.monotonic() - start_time < MOUNT_PUT_FILE_CLIENT_TIMEOUT:
|
|
547
|
-
response = await
|
|
554
|
+
response = await load_context.client.stub.MountPutFile(request2, retry=Retry(base_delay=1))
|
|
548
555
|
if response.exists:
|
|
549
556
|
n_finished += 1
|
|
550
557
|
return mount_file
|
|
@@ -552,7 +559,7 @@ class _Mount(_Object, type_prefix="mo"):
|
|
|
552
559
|
raise modal.exception.MountUploadTimeoutError(f"Mounting of {file_spec.source_description} timed out")
|
|
553
560
|
|
|
554
561
|
# Upload files, or check if they already exist.
|
|
555
|
-
n_concurrent_uploads =
|
|
562
|
+
n_concurrent_uploads = 64
|
|
556
563
|
files: list[api_pb2.MountFile] = []
|
|
557
564
|
async with aclosing(
|
|
558
565
|
async_map(_Mount._get_files(self._entries), _put_file, concurrency=n_concurrent_uploads)
|
|
@@ -574,28 +581,28 @@ class _Mount(_Object, type_prefix="mo"):
|
|
|
574
581
|
req = api_pb2.MountGetOrCreateRequest(
|
|
575
582
|
deployment_name=self._deployment_name,
|
|
576
583
|
namespace=self._namespace,
|
|
577
|
-
environment_name=
|
|
584
|
+
environment_name=load_context.environment_name,
|
|
578
585
|
object_creation_type=creation_type,
|
|
579
586
|
files=files,
|
|
580
587
|
)
|
|
581
|
-
elif
|
|
588
|
+
elif load_context.app_id is not None:
|
|
582
589
|
req = api_pb2.MountGetOrCreateRequest(
|
|
583
590
|
object_creation_type=api_pb2.OBJECT_CREATION_TYPE_ANONYMOUS_OWNED_BY_APP,
|
|
584
591
|
files=files,
|
|
585
|
-
app_id=
|
|
592
|
+
app_id=load_context.app_id,
|
|
586
593
|
)
|
|
587
594
|
else:
|
|
588
595
|
req = api_pb2.MountGetOrCreateRequest(
|
|
589
596
|
object_creation_type=api_pb2.OBJECT_CREATION_TYPE_EPHEMERAL,
|
|
590
597
|
files=files,
|
|
591
|
-
environment_name=
|
|
598
|
+
environment_name=load_context.environment_name,
|
|
592
599
|
)
|
|
593
600
|
|
|
594
|
-
resp = await
|
|
601
|
+
resp = await load_context.client.stub.MountGetOrCreate(req, retry=Retry(base_delay=1))
|
|
595
602
|
status_row.finish(f"Created mount {message_label}")
|
|
596
603
|
|
|
597
604
|
logger.debug(f"Uploaded {total_uploads} new files and {total_bytes} bytes in {time.monotonic() - t0}s")
|
|
598
|
-
self._hydrate(resp.mount_id,
|
|
605
|
+
self._hydrate(resp.mount_id, load_context.client, resp.handle_metadata)
|
|
599
606
|
|
|
600
607
|
@staticmethod
|
|
601
608
|
def _from_local_python_packages(
|
|
@@ -628,19 +635,25 @@ class _Mount(_Object, type_prefix="mo"):
|
|
|
628
635
|
*,
|
|
629
636
|
namespace=api_pb2.DEPLOYMENT_NAMESPACE_WORKSPACE,
|
|
630
637
|
environment_name: Optional[str] = None,
|
|
638
|
+
client: Optional[_Client] = None,
|
|
631
639
|
) -> "_Mount":
|
|
632
640
|
"""mdmd:hidden"""
|
|
633
641
|
|
|
634
|
-
async def _load(provider: _Mount, resolver: Resolver, existing_object_id: Optional[str]):
|
|
642
|
+
async def _load(provider: _Mount, resolver: Resolver, load_context, existing_object_id: Optional[str]):
|
|
635
643
|
req = api_pb2.MountGetOrCreateRequest(
|
|
636
644
|
deployment_name=name,
|
|
637
645
|
namespace=namespace,
|
|
638
|
-
environment_name=
|
|
646
|
+
environment_name=load_context.environment_name,
|
|
639
647
|
)
|
|
640
|
-
response = await
|
|
641
|
-
provider._hydrate(response.mount_id,
|
|
642
|
-
|
|
643
|
-
return _Mount._from_loader(
|
|
648
|
+
response = await load_context.client.stub.MountGetOrCreate(req)
|
|
649
|
+
provider._hydrate(response.mount_id, load_context.client, response.handle_metadata)
|
|
650
|
+
|
|
651
|
+
return _Mount._from_loader(
|
|
652
|
+
_load,
|
|
653
|
+
"Mount()",
|
|
654
|
+
hydrate_lazily=True,
|
|
655
|
+
load_context_overrides=LoadContext(environment_name=environment_name, client=client),
|
|
656
|
+
)
|
|
644
657
|
|
|
645
658
|
async def _deploy(
|
|
646
659
|
self: "_Mount",
|
|
@@ -652,15 +665,12 @@ class _Mount(_Object, type_prefix="mo"):
|
|
|
652
665
|
client: Optional[_Client] = None,
|
|
653
666
|
) -> None:
|
|
654
667
|
check_object_name(deployment_name, "Mount")
|
|
655
|
-
environment_name = _get_environment_name(environment_name, resolver=None)
|
|
656
668
|
self._deployment_name = deployment_name
|
|
657
669
|
self._namespace = namespace
|
|
658
|
-
self._environment_name = environment_name
|
|
659
670
|
self._allow_overwrite = allow_overwrite
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
resolver
|
|
663
|
-
await resolver.load(self)
|
|
671
|
+
resolver = Resolver()
|
|
672
|
+
root_metadata = LoadContext(client=client, environment_name=environment_name)
|
|
673
|
+
await resolver.load(self, root_metadata)
|
|
664
674
|
|
|
665
675
|
def _get_metadata(self) -> api_pb2.MountHandleMetadata:
|
|
666
676
|
if self._content_checksum_sha256_hex is None:
|
modal/mount.pyi
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import collections.abc
|
|
2
2
|
import google.protobuf.message
|
|
3
|
+
import modal._load_context
|
|
3
4
|
import modal._object
|
|
4
5
|
import modal._resolver
|
|
5
6
|
import modal._utils.blob_utils
|
|
@@ -154,7 +155,6 @@ class _Mount(modal._object._Object):
|
|
|
154
155
|
_entries: typing.Optional[list[_MountEntry]]
|
|
155
156
|
_deployment_name: typing.Optional[str]
|
|
156
157
|
_namespace: typing.Optional[int]
|
|
157
|
-
_environment_name: typing.Optional[str]
|
|
158
158
|
_allow_overwrite: bool
|
|
159
159
|
_content_checksum_sha256_hex: typing.Optional[str]
|
|
160
160
|
|
|
@@ -216,7 +216,10 @@ class _Mount(modal._object._Object):
|
|
|
216
216
|
entries: list[_MountEntry],
|
|
217
217
|
) -> collections.abc.AsyncGenerator[modal._utils.blob_utils.FileUploadSpec, None]: ...
|
|
218
218
|
async def _load_mount(
|
|
219
|
-
self: _Mount,
|
|
219
|
+
self: _Mount,
|
|
220
|
+
resolver: modal._resolver.Resolver,
|
|
221
|
+
load_context: modal._load_context.LoadContext,
|
|
222
|
+
existing_object_id: typing.Optional[str],
|
|
220
223
|
): ...
|
|
221
224
|
@staticmethod
|
|
222
225
|
def _from_local_python_packages(
|
|
@@ -226,7 +229,13 @@ class _Mount(modal._object._Object):
|
|
|
226
229
|
ignore: typing.Union[typing.Sequence[str], collections.abc.Callable[[pathlib.Path], bool], None] = None,
|
|
227
230
|
) -> _Mount: ...
|
|
228
231
|
@staticmethod
|
|
229
|
-
def from_name(
|
|
232
|
+
def from_name(
|
|
233
|
+
name: str,
|
|
234
|
+
*,
|
|
235
|
+
namespace=1,
|
|
236
|
+
environment_name: typing.Optional[str] = None,
|
|
237
|
+
client: typing.Optional[modal.client._Client] = None,
|
|
238
|
+
) -> _Mount:
|
|
230
239
|
"""mdmd:hidden"""
|
|
231
240
|
...
|
|
232
241
|
|
|
@@ -269,7 +278,6 @@ class Mount(modal.object.Object):
|
|
|
269
278
|
_entries: typing.Optional[list[_MountEntry]]
|
|
270
279
|
_deployment_name: typing.Optional[str]
|
|
271
280
|
_namespace: typing.Optional[int]
|
|
272
|
-
_environment_name: typing.Optional[str]
|
|
273
281
|
_allow_overwrite: bool
|
|
274
282
|
_content_checksum_sha256_hex: typing.Optional[str]
|
|
275
283
|
|
|
@@ -342,8 +350,20 @@ class Mount(modal.object.Object):
|
|
|
342
350
|
_get_files: ___get_files_spec
|
|
343
351
|
|
|
344
352
|
class ___load_mount_spec(typing_extensions.Protocol[SUPERSELF]):
|
|
345
|
-
def __call__(
|
|
346
|
-
|
|
353
|
+
def __call__(
|
|
354
|
+
self,
|
|
355
|
+
/,
|
|
356
|
+
resolver: modal._resolver.Resolver,
|
|
357
|
+
load_context: modal._load_context.LoadContext,
|
|
358
|
+
existing_object_id: typing.Optional[str],
|
|
359
|
+
): ...
|
|
360
|
+
async def aio(
|
|
361
|
+
self,
|
|
362
|
+
/,
|
|
363
|
+
resolver: modal._resolver.Resolver,
|
|
364
|
+
load_context: modal._load_context.LoadContext,
|
|
365
|
+
existing_object_id: typing.Optional[str],
|
|
366
|
+
): ...
|
|
347
367
|
|
|
348
368
|
_load_mount: ___load_mount_spec[typing_extensions.Self]
|
|
349
369
|
|
|
@@ -355,7 +375,13 @@ class Mount(modal.object.Object):
|
|
|
355
375
|
ignore: typing.Union[typing.Sequence[str], collections.abc.Callable[[pathlib.Path], bool], None] = None,
|
|
356
376
|
) -> Mount: ...
|
|
357
377
|
@staticmethod
|
|
358
|
-
def from_name(
|
|
378
|
+
def from_name(
|
|
379
|
+
name: str,
|
|
380
|
+
*,
|
|
381
|
+
namespace=1,
|
|
382
|
+
environment_name: typing.Optional[str] = None,
|
|
383
|
+
client: typing.Optional[modal.client.Client] = None,
|
|
384
|
+
) -> Mount:
|
|
359
385
|
"""mdmd:hidden"""
|
|
360
386
|
...
|
|
361
387
|
|
modal/network_file_system.py
CHANGED
|
@@ -11,6 +11,7 @@ from synchronicity.async_wrap import asynccontextmanager
|
|
|
11
11
|
import modal
|
|
12
12
|
from modal_proto import api_pb2
|
|
13
13
|
|
|
14
|
+
from ._load_context import LoadContext
|
|
14
15
|
from ._object import (
|
|
15
16
|
EPHEMERAL_OBJECT_HEARTBEAT_SLEEP,
|
|
16
17
|
_get_environment_name,
|
|
@@ -95,6 +96,7 @@ class _NetworkFileSystem(_Object, type_prefix="sv"):
|
|
|
95
96
|
namespace=None, # mdmd:line-hidden
|
|
96
97
|
environment_name: Optional[str] = None,
|
|
97
98
|
create_if_missing: bool = False,
|
|
99
|
+
client: Optional[_Client] = None,
|
|
98
100
|
) -> "_NetworkFileSystem":
|
|
99
101
|
"""Reference a NetworkFileSystem by its name, creating if necessary.
|
|
100
102
|
|
|
@@ -113,15 +115,17 @@ class _NetworkFileSystem(_Object, type_prefix="sv"):
|
|
|
113
115
|
check_object_name(name, "NetworkFileSystem")
|
|
114
116
|
warn_if_passing_namespace(namespace, "modal.NetworkFileSystem.from_name")
|
|
115
117
|
|
|
116
|
-
async def _load(
|
|
118
|
+
async def _load(
|
|
119
|
+
self: _NetworkFileSystem, resolver: Resolver, load_context: LoadContext, existing_object_id: Optional[str]
|
|
120
|
+
):
|
|
117
121
|
req = api_pb2.SharedVolumeGetOrCreateRequest(
|
|
118
122
|
deployment_name=name,
|
|
119
|
-
environment_name=
|
|
123
|
+
environment_name=load_context.environment_name,
|
|
120
124
|
object_creation_type=(api_pb2.OBJECT_CREATION_TYPE_CREATE_IF_MISSING if create_if_missing else None),
|
|
121
125
|
)
|
|
122
126
|
try:
|
|
123
|
-
response = await
|
|
124
|
-
self._hydrate(response.shared_volume_id,
|
|
127
|
+
response = await load_context.client.stub.SharedVolumeGetOrCreate(req)
|
|
128
|
+
self._hydrate(response.shared_volume_id, load_context.client, None)
|
|
125
129
|
except modal.exception.NotFoundError as exc:
|
|
126
130
|
if exc.args[0] == "App has wrong entity vo":
|
|
127
131
|
raise InvalidError(
|
|
@@ -129,7 +133,12 @@ class _NetworkFileSystem(_Object, type_prefix="sv"):
|
|
|
129
133
|
)
|
|
130
134
|
raise
|
|
131
135
|
|
|
132
|
-
return _NetworkFileSystem._from_loader(
|
|
136
|
+
return _NetworkFileSystem._from_loader(
|
|
137
|
+
_load,
|
|
138
|
+
"NetworkFileSystem()",
|
|
139
|
+
hydrate_lazily=True,
|
|
140
|
+
load_context_overrides=LoadContext(environment_name=environment_name, client=client),
|
|
141
|
+
)
|
|
133
142
|
|
|
134
143
|
@classmethod
|
|
135
144
|
@asynccontextmanager
|
modal/network_file_system.pyi
CHANGED
|
@@ -54,7 +54,12 @@ class _NetworkFileSystem(modal._object._Object):
|
|
|
54
54
|
"""
|
|
55
55
|
@staticmethod
|
|
56
56
|
def from_name(
|
|
57
|
-
name: str,
|
|
57
|
+
name: str,
|
|
58
|
+
*,
|
|
59
|
+
namespace=None,
|
|
60
|
+
environment_name: typing.Optional[str] = None,
|
|
61
|
+
create_if_missing: bool = False,
|
|
62
|
+
client: typing.Optional[modal.client._Client] = None,
|
|
58
63
|
) -> _NetworkFileSystem:
|
|
59
64
|
"""Reference a NetworkFileSystem by its name, creating if necessary.
|
|
60
65
|
|
|
@@ -210,7 +215,12 @@ class NetworkFileSystem(modal.object.Object):
|
|
|
210
215
|
|
|
211
216
|
@staticmethod
|
|
212
217
|
def from_name(
|
|
213
|
-
name: str,
|
|
218
|
+
name: str,
|
|
219
|
+
*,
|
|
220
|
+
namespace=None,
|
|
221
|
+
environment_name: typing.Optional[str] = None,
|
|
222
|
+
create_if_missing: bool = False,
|
|
223
|
+
client: typing.Optional[modal.client.Client] = None,
|
|
214
224
|
) -> NetworkFileSystem:
|
|
215
225
|
"""Reference a NetworkFileSystem by its name, creating if necessary.
|
|
216
226
|
|
modal/object.pyi
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import collections.abc
|
|
2
2
|
import google.protobuf.message
|
|
3
|
+
import modal._load_context
|
|
3
4
|
import modal._resolver
|
|
4
5
|
import modal.client
|
|
5
6
|
import typing
|
|
@@ -12,12 +13,14 @@ class Object:
|
|
|
12
13
|
_prefix_to_type: typing.ClassVar[dict[str, type]]
|
|
13
14
|
_load: typing.Optional[
|
|
14
15
|
collections.abc.Callable[
|
|
15
|
-
[typing_extensions.Self, modal._resolver.Resolver, typing.Optional[str]],
|
|
16
|
+
[typing_extensions.Self, modal._resolver.Resolver, modal._load_context.LoadContext, typing.Optional[str]],
|
|
17
|
+
collections.abc.Awaitable[None],
|
|
16
18
|
]
|
|
17
19
|
]
|
|
18
20
|
_preload: typing.Optional[
|
|
19
21
|
collections.abc.Callable[
|
|
20
|
-
[typing_extensions.Self, modal._resolver.Resolver, typing.Optional[str]],
|
|
22
|
+
[typing_extensions.Self, modal._resolver.Resolver, modal._load_context.LoadContext, typing.Optional[str]],
|
|
23
|
+
collections.abc.Awaitable[None],
|
|
21
24
|
]
|
|
22
25
|
]
|
|
23
26
|
_rep: str
|
|
@@ -27,6 +30,7 @@ class Object:
|
|
|
27
30
|
_deduplication_key: typing.Optional[
|
|
28
31
|
collections.abc.Callable[[], collections.abc.Awaitable[collections.abc.Hashable]]
|
|
29
32
|
]
|
|
33
|
+
_load_context_overrides: modal._load_context.LoadContext
|
|
30
34
|
_object_id: typing.Optional[str]
|
|
31
35
|
_client: typing.Optional[modal.client.Client]
|
|
32
36
|
_is_hydrated: bool
|
|
@@ -46,16 +50,22 @@ class Object:
|
|
|
46
50
|
/,
|
|
47
51
|
rep: str,
|
|
48
52
|
load: typing.Optional[
|
|
49
|
-
collections.abc.Callable[
|
|
53
|
+
collections.abc.Callable[
|
|
54
|
+
[SUPERSELF, modal._resolver.Resolver, modal._load_context.LoadContext, typing.Optional[str]], None
|
|
55
|
+
]
|
|
50
56
|
] = None,
|
|
51
57
|
is_another_app: bool = False,
|
|
52
58
|
preload: typing.Optional[
|
|
53
|
-
collections.abc.Callable[
|
|
59
|
+
collections.abc.Callable[
|
|
60
|
+
[SUPERSELF, modal._resolver.Resolver, modal._load_context.LoadContext, typing.Optional[str]], None
|
|
61
|
+
]
|
|
54
62
|
] = None,
|
|
55
63
|
hydrate_lazily: bool = False,
|
|
56
64
|
deps: typing.Optional[collections.abc.Callable[..., collections.abc.Sequence[Object]]] = None,
|
|
57
65
|
deduplication_key: typing.Optional[collections.abc.Callable[[], collections.abc.Hashable]] = None,
|
|
58
66
|
name: typing.Optional[str] = None,
|
|
67
|
+
*,
|
|
68
|
+
load_context_overrides: typing.Optional[modal._load_context.LoadContext] = None,
|
|
59
69
|
): ...
|
|
60
70
|
def aio(
|
|
61
71
|
self,
|
|
@@ -63,13 +73,15 @@ class Object:
|
|
|
63
73
|
rep: str,
|
|
64
74
|
load: typing.Optional[
|
|
65
75
|
collections.abc.Callable[
|
|
66
|
-
[SUPERSELF, modal._resolver.Resolver, typing.Optional[str]],
|
|
76
|
+
[SUPERSELF, modal._resolver.Resolver, modal._load_context.LoadContext, typing.Optional[str]],
|
|
77
|
+
collections.abc.Awaitable[None],
|
|
67
78
|
]
|
|
68
79
|
] = None,
|
|
69
80
|
is_another_app: bool = False,
|
|
70
81
|
preload: typing.Optional[
|
|
71
82
|
collections.abc.Callable[
|
|
72
|
-
[SUPERSELF, modal._resolver.Resolver, typing.Optional[str]],
|
|
83
|
+
[SUPERSELF, modal._resolver.Resolver, modal._load_context.LoadContext, typing.Optional[str]],
|
|
84
|
+
collections.abc.Awaitable[None],
|
|
73
85
|
]
|
|
74
86
|
] = None,
|
|
75
87
|
hydrate_lazily: bool = False,
|
|
@@ -78,6 +90,8 @@ class Object:
|
|
|
78
90
|
collections.abc.Callable[[], collections.abc.Awaitable[collections.abc.Hashable]]
|
|
79
91
|
] = None,
|
|
80
92
|
name: typing.Optional[str] = None,
|
|
93
|
+
*,
|
|
94
|
+
load_context_overrides: typing.Optional[modal._load_context.LoadContext] = None,
|
|
81
95
|
): ...
|
|
82
96
|
|
|
83
97
|
_init: ___init_spec[typing_extensions.Self]
|
|
@@ -101,16 +115,29 @@ class Object:
|
|
|
101
115
|
@classmethod
|
|
102
116
|
def _from_loader(
|
|
103
117
|
cls,
|
|
104
|
-
load: collections.abc.Callable[
|
|
118
|
+
load: collections.abc.Callable[
|
|
119
|
+
[typing_extensions.Self, modal._resolver.Resolver, modal._load_context.LoadContext, typing.Optional[str]],
|
|
120
|
+
None,
|
|
121
|
+
],
|
|
105
122
|
rep: str,
|
|
106
123
|
is_another_app: bool = False,
|
|
107
124
|
preload: typing.Optional[
|
|
108
|
-
collections.abc.Callable[
|
|
125
|
+
collections.abc.Callable[
|
|
126
|
+
[
|
|
127
|
+
typing_extensions.Self,
|
|
128
|
+
modal._resolver.Resolver,
|
|
129
|
+
modal._load_context.LoadContext,
|
|
130
|
+
typing.Optional[str],
|
|
131
|
+
],
|
|
132
|
+
None,
|
|
133
|
+
]
|
|
109
134
|
] = None,
|
|
110
135
|
hydrate_lazily: bool = False,
|
|
111
136
|
deps: typing.Optional[collections.abc.Callable[..., collections.abc.Sequence[Object]]] = None,
|
|
112
137
|
deduplication_key: typing.Optional[collections.abc.Callable[[], collections.abc.Hashable]] = None,
|
|
113
138
|
name: typing.Optional[str] = None,
|
|
139
|
+
*,
|
|
140
|
+
load_context_overrides: modal._load_context.LoadContext,
|
|
114
141
|
): ...
|
|
115
142
|
@staticmethod
|
|
116
143
|
def _get_type_from_id(object_id: str) -> type[Object]: ...
|
modal/proxy.py
CHANGED
|
@@ -3,9 +3,11 @@ from typing import Optional
|
|
|
3
3
|
|
|
4
4
|
from modal_proto import api_pb2
|
|
5
5
|
|
|
6
|
-
from .
|
|
6
|
+
from ._load_context import LoadContext
|
|
7
|
+
from ._object import _Object
|
|
7
8
|
from ._resolver import Resolver
|
|
8
9
|
from ._utils.async_utils import synchronize_api
|
|
10
|
+
from .client import _Client
|
|
9
11
|
|
|
10
12
|
|
|
11
13
|
class _Proxy(_Object, type_prefix="pr"):
|
|
@@ -20,6 +22,7 @@ class _Proxy(_Object, type_prefix="pr"):
|
|
|
20
22
|
name: str,
|
|
21
23
|
*,
|
|
22
24
|
environment_name: Optional[str] = None,
|
|
25
|
+
client: Optional[_Client] = None,
|
|
23
26
|
) -> "_Proxy":
|
|
24
27
|
"""Reference a Proxy by its name.
|
|
25
28
|
|
|
@@ -28,16 +31,21 @@ class _Proxy(_Object, type_prefix="pr"):
|
|
|
28
31
|
|
|
29
32
|
"""
|
|
30
33
|
|
|
31
|
-
async def _load(self: _Proxy, resolver: Resolver, existing_object_id: Optional[str]):
|
|
34
|
+
async def _load(self: _Proxy, resolver: Resolver, load_context: LoadContext, existing_object_id: Optional[str]):
|
|
32
35
|
req = api_pb2.ProxyGetRequest(
|
|
33
36
|
name=name,
|
|
34
|
-
environment_name=
|
|
37
|
+
environment_name=load_context.environment_name,
|
|
35
38
|
)
|
|
36
|
-
response: api_pb2.ProxyGetResponse = await
|
|
37
|
-
self._hydrate(response.proxy.proxy_id,
|
|
39
|
+
response: api_pb2.ProxyGetResponse = await load_context.client.stub.ProxyGet(req)
|
|
40
|
+
self._hydrate(response.proxy.proxy_id, load_context.client, None)
|
|
38
41
|
|
|
39
42
|
rep = _Proxy._repr(name, environment_name)
|
|
40
|
-
return _Proxy._from_loader(
|
|
43
|
+
return _Proxy._from_loader(
|
|
44
|
+
_load,
|
|
45
|
+
rep,
|
|
46
|
+
is_another_app=True,
|
|
47
|
+
load_context_overrides=LoadContext(client=client, environment_name=environment_name),
|
|
48
|
+
)
|
|
41
49
|
|
|
42
50
|
|
|
43
51
|
Proxy = synchronize_api(_Proxy, target_module=__name__)
|
modal/proxy.pyi
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import modal._object
|
|
2
|
+
import modal.client
|
|
2
3
|
import modal.object
|
|
3
4
|
import typing
|
|
4
5
|
|
|
@@ -9,7 +10,12 @@ class _Proxy(modal._object._Object):
|
|
|
9
10
|
a database. See [the guide](https://modal.com/docs/guide/proxy-ips) for more information.
|
|
10
11
|
"""
|
|
11
12
|
@staticmethod
|
|
12
|
-
def from_name(
|
|
13
|
+
def from_name(
|
|
14
|
+
name: str,
|
|
15
|
+
*,
|
|
16
|
+
environment_name: typing.Optional[str] = None,
|
|
17
|
+
client: typing.Optional[modal.client._Client] = None,
|
|
18
|
+
) -> _Proxy:
|
|
13
19
|
"""Reference a Proxy by its name.
|
|
14
20
|
|
|
15
21
|
In contrast to most other Modal objects, new Proxy objects must be
|
|
@@ -28,7 +34,9 @@ class Proxy(modal.object.Object):
|
|
|
28
34
|
...
|
|
29
35
|
|
|
30
36
|
@staticmethod
|
|
31
|
-
def from_name(
|
|
37
|
+
def from_name(
|
|
38
|
+
name: str, *, environment_name: typing.Optional[str] = None, client: typing.Optional[modal.client.Client] = None
|
|
39
|
+
) -> Proxy:
|
|
32
40
|
"""Reference a Proxy by its name.
|
|
33
41
|
|
|
34
42
|
In contrast to most other Modal objects, new Proxy objects must be
|