modal 1.0.6.dev58__py3-none-any.whl → 1.2.3.dev7__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.
Potentially problematic release.
This version of modal might be problematic. Click here for more details.
- modal/__main__.py +3 -4
- modal/_billing.py +80 -0
- modal/_clustered_functions.py +7 -3
- modal/_clustered_functions.pyi +4 -2
- modal/_container_entrypoint.py +41 -49
- modal/_functions.py +424 -195
- modal/_grpc_client.py +171 -0
- modal/_load_context.py +105 -0
- modal/_object.py +68 -20
- modal/_output.py +58 -45
- modal/_partial_function.py +36 -11
- modal/_pty.py +7 -3
- modal/_resolver.py +21 -35
- modal/_runtime/asgi.py +4 -3
- modal/_runtime/container_io_manager.py +301 -186
- modal/_runtime/container_io_manager.pyi +70 -61
- modal/_runtime/execution_context.py +18 -2
- modal/_runtime/execution_context.pyi +4 -1
- modal/_runtime/gpu_memory_snapshot.py +170 -63
- modal/_runtime/user_code_imports.py +28 -58
- modal/_serialization.py +57 -1
- modal/_utils/async_utils.py +33 -12
- modal/_utils/auth_token_manager.py +2 -5
- modal/_utils/blob_utils.py +110 -53
- modal/_utils/function_utils.py +49 -42
- modal/_utils/grpc_utils.py +80 -50
- modal/_utils/mount_utils.py +26 -1
- modal/_utils/name_utils.py +17 -3
- modal/_utils/task_command_router_client.py +536 -0
- modal/_utils/time_utils.py +34 -6
- modal/app.py +219 -83
- modal/app.pyi +229 -56
- modal/billing.py +5 -0
- modal/{requirements → builder}/2025.06.txt +1 -0
- modal/{requirements → builder}/PREVIEW.txt +1 -0
- modal/cli/_download.py +19 -3
- modal/cli/_traceback.py +3 -2
- modal/cli/app.py +4 -4
- modal/cli/cluster.py +15 -7
- modal/cli/config.py +5 -3
- modal/cli/container.py +7 -6
- modal/cli/dict.py +22 -16
- modal/cli/entry_point.py +12 -5
- modal/cli/environment.py +5 -4
- modal/cli/import_refs.py +3 -3
- modal/cli/launch.py +102 -5
- modal/cli/network_file_system.py +9 -13
- modal/cli/profile.py +3 -2
- modal/cli/programs/launch_instance_ssh.py +94 -0
- modal/cli/programs/run_jupyter.py +1 -1
- modal/cli/programs/run_marimo.py +95 -0
- modal/cli/programs/vscode.py +1 -1
- modal/cli/queues.py +57 -26
- modal/cli/run.py +58 -16
- modal/cli/secret.py +48 -22
- modal/cli/utils.py +3 -4
- modal/cli/volume.py +28 -25
- modal/client.py +13 -116
- modal/client.pyi +9 -91
- modal/cloud_bucket_mount.py +5 -3
- modal/cloud_bucket_mount.pyi +5 -1
- modal/cls.py +130 -102
- modal/cls.pyi +45 -85
- modal/config.py +29 -10
- modal/container_process.py +291 -13
- modal/container_process.pyi +95 -32
- modal/dict.py +282 -63
- modal/dict.pyi +423 -73
- modal/environments.py +15 -27
- modal/environments.pyi +5 -15
- modal/exception.py +8 -0
- modal/experimental/__init__.py +143 -38
- modal/experimental/flash.py +247 -78
- modal/experimental/flash.pyi +137 -9
- modal/file_io.py +14 -28
- modal/file_io.pyi +2 -2
- modal/file_pattern_matcher.py +25 -16
- modal/functions.pyi +134 -61
- modal/image.py +255 -86
- modal/image.pyi +300 -62
- modal/io_streams.py +436 -126
- modal/io_streams.pyi +236 -171
- modal/mount.py +62 -157
- modal/mount.pyi +45 -172
- modal/network_file_system.py +30 -53
- modal/network_file_system.pyi +16 -76
- modal/object.pyi +42 -8
- modal/parallel_map.py +821 -113
- modal/parallel_map.pyi +134 -0
- modal/partial_function.pyi +4 -1
- modal/proxy.py +16 -7
- modal/proxy.pyi +10 -2
- modal/queue.py +263 -61
- modal/queue.pyi +409 -66
- modal/runner.py +112 -92
- modal/runner.pyi +45 -27
- modal/sandbox.py +451 -124
- modal/sandbox.pyi +513 -67
- modal/secret.py +291 -67
- modal/secret.pyi +425 -19
- modal/serving.py +7 -11
- modal/serving.pyi +7 -8
- modal/snapshot.py +11 -8
- modal/token_flow.py +4 -4
- modal/volume.py +344 -98
- modal/volume.pyi +464 -68
- {modal-1.0.6.dev58.dist-info → modal-1.2.3.dev7.dist-info}/METADATA +9 -8
- modal-1.2.3.dev7.dist-info/RECORD +195 -0
- modal_docs/mdmd/mdmd.py +11 -1
- modal_proto/api.proto +399 -67
- modal_proto/api_grpc.py +241 -1
- modal_proto/api_pb2.py +1395 -1000
- modal_proto/api_pb2.pyi +1239 -79
- modal_proto/api_pb2_grpc.py +499 -4
- modal_proto/api_pb2_grpc.pyi +162 -14
- modal_proto/modal_api_grpc.py +175 -160
- modal_proto/sandbox_router.proto +145 -0
- modal_proto/sandbox_router_grpc.py +105 -0
- modal_proto/sandbox_router_pb2.py +149 -0
- modal_proto/sandbox_router_pb2.pyi +333 -0
- modal_proto/sandbox_router_pb2_grpc.py +203 -0
- modal_proto/sandbox_router_pb2_grpc.pyi +75 -0
- modal_proto/task_command_router.proto +144 -0
- modal_proto/task_command_router_grpc.py +105 -0
- modal_proto/task_command_router_pb2.py +149 -0
- modal_proto/task_command_router_pb2.pyi +333 -0
- modal_proto/task_command_router_pb2_grpc.py +203 -0
- modal_proto/task_command_router_pb2_grpc.pyi +75 -0
- modal_version/__init__.py +1 -1
- modal-1.0.6.dev58.dist-info/RECORD +0 -183
- modal_proto/modal_options_grpc.py +0 -3
- modal_proto/options.proto +0 -19
- modal_proto/options_grpc.py +0 -3
- modal_proto/options_pb2.py +0 -35
- modal_proto/options_pb2.pyi +0 -20
- modal_proto/options_pb2_grpc.py +0 -4
- modal_proto/options_pb2_grpc.pyi +0 -7
- /modal/{requirements → builder}/2023.12.312.txt +0 -0
- /modal/{requirements → builder}/2023.12.txt +0 -0
- /modal/{requirements → builder}/2024.04.txt +0 -0
- /modal/{requirements → builder}/2024.10.txt +0 -0
- /modal/{requirements → builder}/README.md +0 -0
- /modal/{requirements → builder}/base-images.json +0 -0
- {modal-1.0.6.dev58.dist-info → modal-1.2.3.dev7.dist-info}/WHEEL +0 -0
- {modal-1.0.6.dev58.dist-info → modal-1.2.3.dev7.dist-info}/entry_points.txt +0 -0
- {modal-1.0.6.dev58.dist-info → modal-1.2.3.dev7.dist-info}/licenses/LICENSE +0 -0
- {modal-1.0.6.dev58.dist-info → modal-1.2.3.dev7.dist-info}/top_level.txt +0 -0
modal/mount.py
CHANGED
|
@@ -13,18 +13,19 @@ from pathlib import Path, PurePosixPath
|
|
|
13
13
|
from typing import Callable, Optional, Sequence, Union
|
|
14
14
|
|
|
15
15
|
from google.protobuf.message import Message
|
|
16
|
+
from grpclib import GRPCError
|
|
16
17
|
|
|
17
18
|
import modal.exception
|
|
18
19
|
import modal.file_pattern_matcher
|
|
19
20
|
from modal_proto import api_pb2
|
|
20
21
|
from modal_version import __version__
|
|
21
22
|
|
|
22
|
-
from .
|
|
23
|
+
from ._load_context import LoadContext
|
|
24
|
+
from ._object import _Object
|
|
23
25
|
from ._resolver import Resolver
|
|
24
26
|
from ._utils.async_utils import TaskContext, aclosing, async_map, synchronize_api
|
|
25
27
|
from ._utils.blob_utils import FileUploadSpec, blob_upload_file, get_file_upload_spec_from_path
|
|
26
|
-
from ._utils.
|
|
27
|
-
from ._utils.grpc_utils import retry_transient_errors
|
|
28
|
+
from ._utils.grpc_utils import Retry
|
|
28
29
|
from ._utils.name_utils import check_object_name
|
|
29
30
|
from ._utils.package_utils import get_module_mount_info
|
|
30
31
|
from .client import _Client
|
|
@@ -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
|
|
@@ -411,39 +417,6 @@ class _Mount(_Object, type_prefix="mo"):
|
|
|
411
417
|
),
|
|
412
418
|
)
|
|
413
419
|
|
|
414
|
-
@staticmethod
|
|
415
|
-
def from_local_dir(
|
|
416
|
-
local_path: Union[str, Path],
|
|
417
|
-
*,
|
|
418
|
-
# Where the directory is placed within in the mount
|
|
419
|
-
remote_path: Union[str, PurePosixPath, None] = None,
|
|
420
|
-
# Predicate filter function for file selection, which should accept a filepath and return `True` for inclusion.
|
|
421
|
-
# Defaults to including all files.
|
|
422
|
-
condition: Optional[Callable[[str], bool]] = None,
|
|
423
|
-
# add files from subdirectories as well
|
|
424
|
-
recursive: bool = True,
|
|
425
|
-
) -> "_Mount":
|
|
426
|
-
"""
|
|
427
|
-
**Deprecated:** Use image.add_local_dir() instead
|
|
428
|
-
|
|
429
|
-
Create a `Mount` from a local directory.
|
|
430
|
-
|
|
431
|
-
**Usage**
|
|
432
|
-
|
|
433
|
-
```python notest
|
|
434
|
-
assets = modal.Mount.from_local_dir(
|
|
435
|
-
"~/assets",
|
|
436
|
-
condition=lambda pth: not ".venv" in pth,
|
|
437
|
-
remote_path="/assets",
|
|
438
|
-
)
|
|
439
|
-
```
|
|
440
|
-
"""
|
|
441
|
-
deprecation_warning(
|
|
442
|
-
(2025, 1, 8),
|
|
443
|
-
MOUNT_DEPRECATION_MESSAGE_PATTERN.format(replacement="image.add_local_dir"),
|
|
444
|
-
)
|
|
445
|
-
return _Mount._from_local_dir(local_path, remote_path=remote_path, condition=condition, recursive=recursive)
|
|
446
|
-
|
|
447
420
|
@staticmethod
|
|
448
421
|
def _from_local_dir(
|
|
449
422
|
local_path: Union[str, Path],
|
|
@@ -479,29 +452,6 @@ class _Mount(_Object, type_prefix="mo"):
|
|
|
479
452
|
),
|
|
480
453
|
)
|
|
481
454
|
|
|
482
|
-
@staticmethod
|
|
483
|
-
def from_local_file(local_path: Union[str, Path], remote_path: Union[str, PurePosixPath, None] = None) -> "_Mount":
|
|
484
|
-
"""
|
|
485
|
-
**Deprecated**: Use image.add_local_file() instead
|
|
486
|
-
|
|
487
|
-
Create a `Mount` mounting a single local file.
|
|
488
|
-
|
|
489
|
-
**Usage**
|
|
490
|
-
|
|
491
|
-
```python notest
|
|
492
|
-
# Mount the DBT profile in user's home directory into container.
|
|
493
|
-
dbt_profiles = modal.Mount.from_local_file(
|
|
494
|
-
local_path="~/profiles.yml",
|
|
495
|
-
remote_path="/root/dbt_profile/profiles.yml",
|
|
496
|
-
)
|
|
497
|
-
```
|
|
498
|
-
"""
|
|
499
|
-
deprecation_warning(
|
|
500
|
-
(2025, 1, 8),
|
|
501
|
-
MOUNT_DEPRECATION_MESSAGE_PATTERN.format(replacement="image.add_local_file"),
|
|
502
|
-
)
|
|
503
|
-
return _Mount._from_local_file(local_path, remote_path)
|
|
504
|
-
|
|
505
455
|
@staticmethod
|
|
506
456
|
def _from_local_file(local_path: Union[str, Path], remote_path: Union[str, PurePosixPath, None] = None) -> "_Mount":
|
|
507
457
|
return _Mount._new().add_local_file(local_path, remote_path=remote_path)
|
|
@@ -533,6 +483,7 @@ class _Mount(_Object, type_prefix="mo"):
|
|
|
533
483
|
async def _load_mount(
|
|
534
484
|
self: "_Mount",
|
|
535
485
|
resolver: Resolver,
|
|
486
|
+
load_context: LoadContext,
|
|
536
487
|
existing_object_id: Optional[str],
|
|
537
488
|
):
|
|
538
489
|
t0 = time.monotonic()
|
|
@@ -574,7 +525,7 @@ class _Mount(_Object, type_prefix="mo"):
|
|
|
574
525
|
|
|
575
526
|
request = api_pb2.MountPutFileRequest(sha256_hex=file_spec.sha256_hex)
|
|
576
527
|
accounted_hashes.add(file_spec.sha256_hex)
|
|
577
|
-
response = await
|
|
528
|
+
response = await load_context.client.stub.MountPutFile(request, retry=Retry(base_delay=1))
|
|
578
529
|
|
|
579
530
|
if response.exists:
|
|
580
531
|
n_finished += 1
|
|
@@ -588,7 +539,7 @@ class _Mount(_Object, type_prefix="mo"):
|
|
|
588
539
|
async with blob_upload_concurrency:
|
|
589
540
|
with file_spec.source() as fp:
|
|
590
541
|
blob_id = await blob_upload_file(
|
|
591
|
-
fp,
|
|
542
|
+
fp, load_context.client.stub, sha256_hex=file_spec.sha256_hex, md5_hex=file_spec.md5_hex
|
|
592
543
|
)
|
|
593
544
|
logger.debug(f"Uploading blob file {file_spec.source_description} as {remote_filename}")
|
|
594
545
|
request2 = api_pb2.MountPutFileRequest(data_blob_id=blob_id, sha256_hex=file_spec.sha256_hex)
|
|
@@ -600,7 +551,7 @@ class _Mount(_Object, type_prefix="mo"):
|
|
|
600
551
|
|
|
601
552
|
start_time = time.monotonic()
|
|
602
553
|
while time.monotonic() - start_time < MOUNT_PUT_FILE_CLIENT_TIMEOUT:
|
|
603
|
-
response = await
|
|
554
|
+
response = await load_context.client.stub.MountPutFile(request2, retry=Retry(base_delay=1))
|
|
604
555
|
if response.exists:
|
|
605
556
|
n_finished += 1
|
|
606
557
|
return mount_file
|
|
@@ -608,7 +559,7 @@ class _Mount(_Object, type_prefix="mo"):
|
|
|
608
559
|
raise modal.exception.MountUploadTimeoutError(f"Mounting of {file_spec.source_description} timed out")
|
|
609
560
|
|
|
610
561
|
# Upload files, or check if they already exist.
|
|
611
|
-
n_concurrent_uploads =
|
|
562
|
+
n_concurrent_uploads = 64
|
|
612
563
|
files: list[api_pb2.MountFile] = []
|
|
613
564
|
async with aclosing(
|
|
614
565
|
async_map(_Mount._get_files(self._entries), _put_file, concurrency=n_concurrent_uploads)
|
|
@@ -630,67 +581,28 @@ class _Mount(_Object, type_prefix="mo"):
|
|
|
630
581
|
req = api_pb2.MountGetOrCreateRequest(
|
|
631
582
|
deployment_name=self._deployment_name,
|
|
632
583
|
namespace=self._namespace,
|
|
633
|
-
environment_name=
|
|
584
|
+
environment_name=load_context.environment_name,
|
|
634
585
|
object_creation_type=creation_type,
|
|
635
586
|
files=files,
|
|
636
587
|
)
|
|
637
|
-
elif
|
|
588
|
+
elif load_context.app_id is not None:
|
|
638
589
|
req = api_pb2.MountGetOrCreateRequest(
|
|
639
590
|
object_creation_type=api_pb2.OBJECT_CREATION_TYPE_ANONYMOUS_OWNED_BY_APP,
|
|
640
591
|
files=files,
|
|
641
|
-
app_id=
|
|
592
|
+
app_id=load_context.app_id,
|
|
642
593
|
)
|
|
643
594
|
else:
|
|
644
595
|
req = api_pb2.MountGetOrCreateRequest(
|
|
645
596
|
object_creation_type=api_pb2.OBJECT_CREATION_TYPE_EPHEMERAL,
|
|
646
597
|
files=files,
|
|
647
|
-
environment_name=
|
|
598
|
+
environment_name=load_context.environment_name,
|
|
648
599
|
)
|
|
649
600
|
|
|
650
|
-
resp = await
|
|
601
|
+
resp = await load_context.client.stub.MountGetOrCreate(req, retry=Retry(base_delay=1))
|
|
651
602
|
status_row.finish(f"Created mount {message_label}")
|
|
652
603
|
|
|
653
604
|
logger.debug(f"Uploaded {total_uploads} new files and {total_bytes} bytes in {time.monotonic() - t0}s")
|
|
654
|
-
self._hydrate(resp.mount_id,
|
|
655
|
-
|
|
656
|
-
@staticmethod
|
|
657
|
-
def from_local_python_packages(
|
|
658
|
-
*module_names: str,
|
|
659
|
-
remote_dir: Union[str, PurePosixPath] = ROOT_DIR.as_posix(),
|
|
660
|
-
# Predicate filter function for file selection, which should accept a filepath and return `True` for inclusion.
|
|
661
|
-
# Defaults to including all files.
|
|
662
|
-
condition: Optional[Callable[[str], bool]] = None,
|
|
663
|
-
ignore: Optional[Union[Sequence[str], Callable[[Path], bool]]] = None,
|
|
664
|
-
) -> "_Mount":
|
|
665
|
-
"""
|
|
666
|
-
**Deprecated**: Use image.add_local_python_source instead
|
|
667
|
-
|
|
668
|
-
Returns a `modal.Mount` that makes local modules listed in `module_names` available inside the container.
|
|
669
|
-
This works by mounting the local path of each module's package to a directory inside the container
|
|
670
|
-
that's on `PYTHONPATH`.
|
|
671
|
-
|
|
672
|
-
**Usage**
|
|
673
|
-
|
|
674
|
-
```python notest
|
|
675
|
-
import modal
|
|
676
|
-
import my_local_module
|
|
677
|
-
|
|
678
|
-
app = modal.App()
|
|
679
|
-
|
|
680
|
-
@app.function(mounts=[
|
|
681
|
-
modal.Mount.from_local_python_packages("my_local_module", "my_other_module"),
|
|
682
|
-
])
|
|
683
|
-
def f():
|
|
684
|
-
my_local_module.do_stuff()
|
|
685
|
-
```
|
|
686
|
-
"""
|
|
687
|
-
deprecation_warning(
|
|
688
|
-
(2025, 1, 8),
|
|
689
|
-
MOUNT_DEPRECATION_MESSAGE_PATTERN.format(replacement="image.add_local_python_source"),
|
|
690
|
-
)
|
|
691
|
-
return _Mount._from_local_python_packages(
|
|
692
|
-
*module_names, remote_dir=remote_dir, condition=condition, ignore=ignore
|
|
693
|
-
)
|
|
605
|
+
self._hydrate(resp.mount_id, load_context.client, resp.handle_metadata)
|
|
694
606
|
|
|
695
607
|
@staticmethod
|
|
696
608
|
def _from_local_python_packages(
|
|
@@ -723,41 +635,25 @@ class _Mount(_Object, type_prefix="mo"):
|
|
|
723
635
|
*,
|
|
724
636
|
namespace=api_pb2.DEPLOYMENT_NAMESPACE_WORKSPACE,
|
|
725
637
|
environment_name: Optional[str] = None,
|
|
638
|
+
client: Optional[_Client] = None,
|
|
726
639
|
) -> "_Mount":
|
|
727
640
|
"""mdmd:hidden"""
|
|
728
641
|
|
|
729
|
-
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]):
|
|
730
643
|
req = api_pb2.MountGetOrCreateRequest(
|
|
731
644
|
deployment_name=name,
|
|
732
645
|
namespace=namespace,
|
|
733
|
-
environment_name=
|
|
646
|
+
environment_name=load_context.environment_name,
|
|
734
647
|
)
|
|
735
|
-
response = await
|
|
736
|
-
provider._hydrate(response.mount_id,
|
|
737
|
-
|
|
738
|
-
return _Mount._from_loader(
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
name: str,
|
|
744
|
-
namespace=api_pb2.DEPLOYMENT_NAMESPACE_WORKSPACE,
|
|
745
|
-
client: Optional[_Client] = None,
|
|
746
|
-
environment_name: Optional[str] = None,
|
|
747
|
-
) -> "_Mount":
|
|
748
|
-
"""mdmd:hidden"""
|
|
749
|
-
deprecation_warning(
|
|
750
|
-
(2025, 1, 27),
|
|
751
|
-
"`modal.Mount.lookup` is deprecated and will be removed in a future release."
|
|
752
|
-
" It can be replaced with `modal.Mount.from_name`."
|
|
753
|
-
"\n\nSee https://modal.com/docs/guide/modal-1-0-migration for more information.",
|
|
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),
|
|
754
656
|
)
|
|
755
|
-
obj = _Mount.from_name(name, namespace=namespace, environment_name=environment_name)
|
|
756
|
-
if client is None:
|
|
757
|
-
client = await _Client.from_env()
|
|
758
|
-
resolver = Resolver(client=client)
|
|
759
|
-
await resolver.load(obj)
|
|
760
|
-
return obj
|
|
761
657
|
|
|
762
658
|
async def _deploy(
|
|
763
659
|
self: "_Mount",
|
|
@@ -769,15 +665,12 @@ class _Mount(_Object, type_prefix="mo"):
|
|
|
769
665
|
client: Optional[_Client] = None,
|
|
770
666
|
) -> None:
|
|
771
667
|
check_object_name(deployment_name, "Mount")
|
|
772
|
-
environment_name = _get_environment_name(environment_name, resolver=None)
|
|
773
668
|
self._deployment_name = deployment_name
|
|
774
669
|
self._namespace = namespace
|
|
775
|
-
self._environment_name = environment_name
|
|
776
670
|
self._allow_overwrite = allow_overwrite
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
resolver
|
|
780
|
-
await resolver.load(self)
|
|
671
|
+
resolver = Resolver()
|
|
672
|
+
root_metadata = LoadContext(client=client, environment_name=environment_name)
|
|
673
|
+
await resolver.load(self, root_metadata)
|
|
781
674
|
|
|
782
675
|
def _get_metadata(self) -> api_pb2.MountHandleMetadata:
|
|
783
676
|
if self._content_checksum_sha256_hex is None:
|
|
@@ -865,6 +758,7 @@ async def _create_single_client_dependency_mount(
|
|
|
865
758
|
uv_python_platform: str,
|
|
866
759
|
check_if_exists: bool = True,
|
|
867
760
|
allow_overwrite: bool = False,
|
|
761
|
+
dry_run: bool = False,
|
|
868
762
|
):
|
|
869
763
|
import tempfile
|
|
870
764
|
|
|
@@ -882,7 +776,7 @@ async def _create_single_client_dependency_mount(
|
|
|
882
776
|
|
|
883
777
|
with tempfile.TemporaryDirectory(ignore_cleanup_errors=True) as tmpd:
|
|
884
778
|
print(f"📦 Building {mount_name}.")
|
|
885
|
-
requirements = os.path.join(os.path.dirname(__file__), f"
|
|
779
|
+
requirements = os.path.join(os.path.dirname(__file__), f"builder/{builder_version}.txt")
|
|
886
780
|
cmd = " ".join(
|
|
887
781
|
[
|
|
888
782
|
"uv",
|
|
@@ -929,20 +823,28 @@ async def _create_single_client_dependency_mount(
|
|
|
929
823
|
remote_path=REMOTE_SITECUSTOMIZE_PATH,
|
|
930
824
|
)
|
|
931
825
|
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
826
|
+
if not dry_run:
|
|
827
|
+
try:
|
|
828
|
+
await python_mount._deploy.aio(
|
|
829
|
+
mount_name,
|
|
830
|
+
api_pb2.DEPLOYMENT_NAMESPACE_GLOBAL,
|
|
831
|
+
environment_name=profile_environment,
|
|
832
|
+
allow_overwrite=allow_overwrite,
|
|
833
|
+
client=client,
|
|
834
|
+
)
|
|
835
|
+
print(f"✅ Deployed mount {mount_name} to global namespace.")
|
|
836
|
+
except GRPCError as e:
|
|
837
|
+
print(f"⚠️ Mount creation failed with {e.status}: {e.message}")
|
|
838
|
+
else:
|
|
839
|
+
print(f"Dry run - skipping deployment of mount {mount_name}")
|
|
940
840
|
|
|
941
841
|
|
|
942
842
|
async def _create_client_dependency_mounts(
|
|
943
843
|
client=None,
|
|
944
844
|
python_versions: list[str] = list(PYTHON_STANDALONE_VERSIONS),
|
|
845
|
+
builder_versions: list[str] = ["2025.06"], # Reenable "PREVIEW" during testing
|
|
945
846
|
check_if_exists=True,
|
|
847
|
+
dry_run=False,
|
|
946
848
|
):
|
|
947
849
|
arch = "x86_64"
|
|
948
850
|
platform_tags = [
|
|
@@ -950,8 +852,8 @@ async def _create_client_dependency_mounts(
|
|
|
950
852
|
("musllinux_1_2", f"{arch}-unknown-linux-musl"), # musl >= 1.2
|
|
951
853
|
]
|
|
952
854
|
coros = []
|
|
953
|
-
for
|
|
954
|
-
for
|
|
855
|
+
for python_version in python_versions:
|
|
856
|
+
for builder_version in builder_versions:
|
|
955
857
|
for platform, uv_python_platform in platform_tags:
|
|
956
858
|
coros.append(
|
|
957
859
|
_create_single_client_dependency_mount(
|
|
@@ -961,9 +863,12 @@ async def _create_client_dependency_mounts(
|
|
|
961
863
|
arch,
|
|
962
864
|
platform,
|
|
963
865
|
uv_python_platform,
|
|
964
|
-
#
|
|
965
|
-
#
|
|
966
|
-
#
|
|
866
|
+
# This check_if_exists / allow_overwrite parameterization is very awkward
|
|
867
|
+
# Also it doesn't provide a hook for overwriting a non-preview version, which
|
|
868
|
+
# in theory we may need to do at some point (hopefully not, but...)
|
|
869
|
+
check_if_exists=check_if_exists and builder_version != "PREVIEW",
|
|
870
|
+
allow_overwrite=builder_version == "PREVIEW",
|
|
871
|
+
dry_run=dry_run,
|
|
967
872
|
)
|
|
968
873
|
)
|
|
969
874
|
await TaskContext.gather(*coros)
|