modAL 1.2.4.dev2__tar.gz → 1.2.5.dev0__tar.gz
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-1.2.4.dev2 → modal-1.2.5.dev0}/PKG-INFO +1 -1
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/cli/entry_point.py +2 -2
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/cli/run.py +3 -222
- modal-1.2.5.dev0/modal/cli/shell.py +237 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/client.pyi +2 -2
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/functions.pyi +6 -6
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal.egg-info/PKG-INFO +1 -1
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal.egg-info/SOURCES.txt +1 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal_version/__init__.py +1 -1
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/LICENSE +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/README.md +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/__init__.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/__main__.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_billing.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_clustered_functions.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_clustered_functions.pyi +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_container_entrypoint.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_functions.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_grpc_client.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_ipython.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_load_context.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_location.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_object.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_output.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_partial_function.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_pty.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_resolver.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_resources.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_runtime/__init__.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_runtime/asgi.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_runtime/container_io_manager.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_runtime/container_io_manager.pyi +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_runtime/execution_context.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_runtime/execution_context.pyi +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_runtime/gpu_memory_snapshot.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_runtime/telemetry.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_runtime/user_code_imports.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_serialization.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_traceback.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_tunnel.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_tunnel.pyi +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_type_manager.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_utils/__init__.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_utils/app_utils.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_utils/async_utils.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_utils/auth_token_manager.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_utils/blob_utils.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_utils/bytes_io_segment_payload.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_utils/deprecation.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_utils/docker_utils.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_utils/function_utils.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_utils/git_utils.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_utils/grpc_testing.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_utils/grpc_utils.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_utils/hash_utils.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_utils/http_utils.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_utils/jwt_utils.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_utils/logger.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_utils/mount_utils.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_utils/name_utils.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_utils/package_utils.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_utils/pattern_utils.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_utils/rand_pb_testing.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_utils/shell_utils.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_utils/task_command_router_client.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_utils/time_utils.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_vendor/__init__.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_vendor/a2wsgi_wsgi.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_vendor/cloudpickle.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_vendor/tblib.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/_watcher.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/app.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/app.pyi +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/billing.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/builder/2023.12.312.txt +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/builder/2023.12.txt +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/builder/2024.04.txt +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/builder/2024.10.txt +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/builder/2025.06.txt +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/builder/PREVIEW.txt +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/builder/README.md +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/builder/base-images.json +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/call_graph.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/cli/__init__.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/cli/_download.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/cli/_traceback.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/cli/app.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/cli/cluster.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/cli/config.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/cli/container.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/cli/dict.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/cli/environment.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/cli/import_refs.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/cli/launch.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/cli/network_file_system.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/cli/profile.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/cli/programs/__init__.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/cli/programs/launch_instance_ssh.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/cli/programs/run_jupyter.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/cli/programs/run_marimo.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/cli/programs/vscode.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/cli/queues.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/cli/secret.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/cli/token.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/cli/utils.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/cli/volume.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/client.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/cloud_bucket_mount.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/cloud_bucket_mount.pyi +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/cls.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/cls.pyi +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/config.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/container_process.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/container_process.pyi +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/dict.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/dict.pyi +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/environments.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/environments.pyi +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/exception.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/experimental/__init__.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/experimental/flash.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/experimental/flash.pyi +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/experimental/ipython.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/file_io.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/file_io.pyi +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/file_pattern_matcher.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/functions.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/gpu.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/image.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/image.pyi +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/io_streams.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/io_streams.pyi +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/mount.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/mount.pyi +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/network_file_system.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/network_file_system.pyi +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/object.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/object.pyi +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/output.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/parallel_map.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/parallel_map.pyi +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/partial_function.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/partial_function.pyi +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/proxy.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/proxy.pyi +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/py.typed +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/queue.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/queue.pyi +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/retries.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/runner.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/runner.pyi +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/running_app.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/sandbox.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/sandbox.pyi +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/schedule.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/scheduler_placement.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/secret.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/secret.pyi +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/serving.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/serving.pyi +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/snapshot.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/snapshot.pyi +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/stream_type.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/token_flow.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/token_flow.pyi +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/volume.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal/volume.pyi +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal.egg-info/dependency_links.txt +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal.egg-info/entry_points.txt +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal.egg-info/requires.txt +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal.egg-info/top_level.txt +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal_docs/__init__.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal_docs/gen_cli_docs.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal_docs/gen_reference_docs.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal_docs/mdmd/__init__.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal_docs/mdmd/mdmd.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal_docs/mdmd/signatures.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal_proto/__init__.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal_proto/api.proto +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal_proto/api_grpc.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal_proto/api_pb2.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal_proto/api_pb2.pyi +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal_proto/api_pb2_grpc.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal_proto/api_pb2_grpc.pyi +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal_proto/modal_api_grpc.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal_proto/py.typed +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal_proto/sandbox_router.proto +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal_proto/sandbox_router_grpc.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal_proto/sandbox_router_pb2.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal_proto/sandbox_router_pb2.pyi +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal_proto/sandbox_router_pb2_grpc.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal_proto/sandbox_router_pb2_grpc.pyi +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal_proto/task_command_router.proto +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal_proto/task_command_router_grpc.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal_proto/task_command_router_pb2.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal_proto/task_command_router_pb2.pyi +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal_proto/task_command_router_pb2_grpc.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal_proto/task_command_router_pb2_grpc.pyi +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/modal_version/__main__.py +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/pyproject.toml +0 -0
- {modal-1.2.4.dev2 → modal-1.2.5.dev0}/setup.cfg +0 -0
|
@@ -8,7 +8,7 @@ from rich.rule import Rule
|
|
|
8
8
|
from modal._output import make_console
|
|
9
9
|
from modal._utils.async_utils import synchronizer
|
|
10
10
|
|
|
11
|
-
from . import run
|
|
11
|
+
from . import run, shell as shell_module
|
|
12
12
|
from .app import app_cli
|
|
13
13
|
from .cluster import cluster_cli
|
|
14
14
|
from .config import config_cli
|
|
@@ -94,7 +94,7 @@ async def setup(profile: Optional[str] = None):
|
|
|
94
94
|
# Commands
|
|
95
95
|
entrypoint_cli_typer.command("deploy", no_args_is_help=True)(run.deploy)
|
|
96
96
|
entrypoint_cli_typer.command("serve", no_args_is_help=True)(run.serve)
|
|
97
|
-
entrypoint_cli_typer.command("shell")(
|
|
97
|
+
entrypoint_cli_typer.command("shell")(shell_module.shell)
|
|
98
98
|
entrypoint_cli_typer.add_typer(launch_cli)
|
|
99
99
|
|
|
100
100
|
# Deployments
|
|
@@ -2,15 +2,11 @@
|
|
|
2
2
|
import asyncio
|
|
3
3
|
import functools
|
|
4
4
|
import inspect
|
|
5
|
-
import platform
|
|
6
5
|
import re
|
|
7
|
-
import shlex
|
|
8
6
|
import sys
|
|
9
7
|
import time
|
|
10
8
|
import typing
|
|
11
9
|
from dataclasses import dataclass
|
|
12
|
-
from functools import partial
|
|
13
|
-
from pathlib import Path, PurePosixPath
|
|
14
10
|
from typing import Any, Callable, Optional
|
|
15
11
|
|
|
16
12
|
import click
|
|
@@ -18,20 +14,15 @@ import typer
|
|
|
18
14
|
from click import ClickException
|
|
19
15
|
from typing_extensions import TypedDict
|
|
20
16
|
|
|
21
|
-
from .._functions import _FunctionSpec
|
|
22
17
|
from ..app import App, LocalEntrypoint
|
|
23
18
|
from ..cls import _get_class_constructor_signature
|
|
24
19
|
from ..config import config
|
|
25
20
|
from ..environments import ensure_env
|
|
26
|
-
from ..exception import ExecutionError, InvalidError,
|
|
21
|
+
from ..exception import ExecutionError, InvalidError, _CliUserExecutionError
|
|
27
22
|
from ..functions import Function
|
|
28
|
-
from ..image import Image
|
|
29
|
-
from ..mount import _Mount
|
|
30
23
|
from ..output import enable_output
|
|
31
|
-
from ..runner import deploy_app,
|
|
32
|
-
from ..secret import Secret
|
|
24
|
+
from ..runner import deploy_app, run_app
|
|
33
25
|
from ..serving import serve_app
|
|
34
|
-
from ..volume import Volume
|
|
35
26
|
from .import_refs import (
|
|
36
27
|
CLICommand,
|
|
37
28
|
MethodReference,
|
|
@@ -40,7 +31,7 @@ from .import_refs import (
|
|
|
40
31
|
import_app_from_ref,
|
|
41
32
|
parse_import_ref,
|
|
42
33
|
)
|
|
43
|
-
from .utils import ENV_OPTION, ENV_OPTION_HELP,
|
|
34
|
+
from .utils import ENV_OPTION, ENV_OPTION_HELP, stream_app_logs
|
|
44
35
|
|
|
45
36
|
|
|
46
37
|
class ParameterMetadata(TypedDict):
|
|
@@ -521,213 +512,3 @@ def serve(
|
|
|
521
512
|
t = min(timeout, 3600)
|
|
522
513
|
time.sleep(t)
|
|
523
514
|
timeout -= t
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
def shell(
|
|
527
|
-
ref: Optional[str] = typer.Argument(
|
|
528
|
-
default=None,
|
|
529
|
-
help=(
|
|
530
|
-
"ID of running container or Sandbox, or path to a Python file containing an App."
|
|
531
|
-
" Can also include a Function specifier, like `module.py::func`, if the file defines multiple Functions."
|
|
532
|
-
),
|
|
533
|
-
),
|
|
534
|
-
cmd: str = typer.Option("/bin/bash", "-c", "--cmd", help="Command to run inside the Modal image."),
|
|
535
|
-
env: str = ENV_OPTION,
|
|
536
|
-
image: Optional[str] = typer.Option(
|
|
537
|
-
default=None, help="Container image tag for inside the shell (if not using REF)."
|
|
538
|
-
),
|
|
539
|
-
add_python: Optional[str] = typer.Option(default=None, help="Add Python to the image (if not using REF)."),
|
|
540
|
-
volume: Optional[list[str]] = typer.Option(
|
|
541
|
-
default=None,
|
|
542
|
-
help=(
|
|
543
|
-
"Name of a `modal.Volume` to mount inside the shell at `/mnt/{name}` (if not using REF)."
|
|
544
|
-
" Can be used multiple times."
|
|
545
|
-
),
|
|
546
|
-
),
|
|
547
|
-
add_local: Optional[list[str]] = typer.Option(
|
|
548
|
-
default=None,
|
|
549
|
-
help=(
|
|
550
|
-
"Local file or directory to mount inside the shell at `/mnt/{basename}` (if not using REF)."
|
|
551
|
-
" Can be used multiple times."
|
|
552
|
-
),
|
|
553
|
-
),
|
|
554
|
-
secret: Optional[list[str]] = typer.Option(
|
|
555
|
-
default=None,
|
|
556
|
-
help=("Name of a `modal.Secret` to mount inside the shell (if not using REF). Can be used multiple times."),
|
|
557
|
-
),
|
|
558
|
-
cpu: Optional[int] = typer.Option(default=None, help="Number of CPUs to allocate to the shell (if not using REF)."),
|
|
559
|
-
memory: Optional[int] = typer.Option(
|
|
560
|
-
default=None, help="Memory to allocate for the shell, in MiB (if not using REF)."
|
|
561
|
-
),
|
|
562
|
-
gpu: Optional[str] = typer.Option(
|
|
563
|
-
default=None,
|
|
564
|
-
help="GPUs to request for the shell, if any. Examples are `any`, `a10g`, `a100:4` (if not using REF).",
|
|
565
|
-
),
|
|
566
|
-
cloud: Optional[str] = typer.Option(
|
|
567
|
-
default=None,
|
|
568
|
-
help=(
|
|
569
|
-
"Cloud provider to run the shell on. Possible values are `aws`, `gcp`, `oci`, `auto` (if not using REF)."
|
|
570
|
-
),
|
|
571
|
-
),
|
|
572
|
-
region: Optional[str] = typer.Option(
|
|
573
|
-
default=None,
|
|
574
|
-
help=(
|
|
575
|
-
"Region(s) to run the container on. "
|
|
576
|
-
"Can be a single region or a comma-separated list to choose from (if not using REF)."
|
|
577
|
-
),
|
|
578
|
-
),
|
|
579
|
-
pty: Optional[bool] = typer.Option(default=None, help="Run the command using a PTY."),
|
|
580
|
-
use_module_mode: bool = typer.Option(
|
|
581
|
-
False, "-m", help="Interpret argument as a Python module path instead of a file/script path"
|
|
582
|
-
),
|
|
583
|
-
):
|
|
584
|
-
"""Run a command or interactive shell inside a Modal container.
|
|
585
|
-
|
|
586
|
-
**Examples:**
|
|
587
|
-
|
|
588
|
-
Start an interactive shell inside the default Debian-based image:
|
|
589
|
-
|
|
590
|
-
```
|
|
591
|
-
modal shell
|
|
592
|
-
```
|
|
593
|
-
|
|
594
|
-
Start an interactive shell with the spec for `my_function` in your App
|
|
595
|
-
(uses the same image, volumes, mounts, etc.):
|
|
596
|
-
|
|
597
|
-
```
|
|
598
|
-
modal shell hello_world.py::my_function
|
|
599
|
-
```
|
|
600
|
-
|
|
601
|
-
Or, if you're using a [modal.Cls](https://modal.com/docs/reference/modal.Cls)
|
|
602
|
-
you can refer to a `@modal.method` directly:
|
|
603
|
-
|
|
604
|
-
```
|
|
605
|
-
modal shell hello_world.py::MyClass.my_method
|
|
606
|
-
```
|
|
607
|
-
|
|
608
|
-
Start a `python` shell:
|
|
609
|
-
|
|
610
|
-
```
|
|
611
|
-
modal shell hello_world.py --cmd=python
|
|
612
|
-
```
|
|
613
|
-
|
|
614
|
-
Run a command with your function's spec and pipe the output to a file:
|
|
615
|
-
|
|
616
|
-
```
|
|
617
|
-
modal shell hello_world.py -c 'uv pip list' > env.txt
|
|
618
|
-
```
|
|
619
|
-
|
|
620
|
-
Connect to a running Sandbox by ID:
|
|
621
|
-
|
|
622
|
-
```
|
|
623
|
-
modal shell sb-abc123xyz
|
|
624
|
-
```
|
|
625
|
-
"""
|
|
626
|
-
env = ensure_env(env)
|
|
627
|
-
|
|
628
|
-
if pty is None:
|
|
629
|
-
pty = is_tty()
|
|
630
|
-
|
|
631
|
-
if platform.system() == "Windows":
|
|
632
|
-
raise InvalidError("`modal shell` is currently not supported on Windows")
|
|
633
|
-
|
|
634
|
-
app = App("modal shell")
|
|
635
|
-
|
|
636
|
-
if ref is not None:
|
|
637
|
-
# `modal shell` with a sandbox ID gets the task_id, that's then handled by the `ta-*` flow below.
|
|
638
|
-
if ref.startswith("sb-") and len(ref[3:]) > 0 and ref[3:].isalnum():
|
|
639
|
-
from ..sandbox import Sandbox
|
|
640
|
-
|
|
641
|
-
try:
|
|
642
|
-
sandbox = Sandbox.from_id(ref)
|
|
643
|
-
task_id = sandbox._get_task_id()
|
|
644
|
-
ref = task_id
|
|
645
|
-
except NotFoundError as e:
|
|
646
|
-
raise ClickException(f"Sandbox '{ref}' not found")
|
|
647
|
-
except Exception as e:
|
|
648
|
-
raise ClickException(f"Error connecting to sandbox '{ref}': {str(e)}")
|
|
649
|
-
|
|
650
|
-
# `modal shell` with a container ID is a special case, alias for `modal container exec`.
|
|
651
|
-
if ref.startswith("ta-") and len(ref[3:]) > 0 and ref[3:].isalnum():
|
|
652
|
-
from .container import exec
|
|
653
|
-
|
|
654
|
-
exec(container_id=ref, command=shlex.split(cmd), pty=pty)
|
|
655
|
-
return
|
|
656
|
-
|
|
657
|
-
import_ref = parse_import_ref(ref, use_module_mode=use_module_mode)
|
|
658
|
-
runnable, all_usable_commands = import_and_filter(
|
|
659
|
-
import_ref, base_cmd="modal shell", accept_local_entrypoint=False, accept_webhook=True
|
|
660
|
-
)
|
|
661
|
-
if not runnable:
|
|
662
|
-
help_header = (
|
|
663
|
-
"Specify a Modal function to start a shell session for. E.g.\n"
|
|
664
|
-
f"> modal shell {import_ref.file_or_module}::my_function"
|
|
665
|
-
)
|
|
666
|
-
|
|
667
|
-
if all_usable_commands:
|
|
668
|
-
help_footer = f"The selected module '{import_ref.file_or_module}' has the following choices:\n\n"
|
|
669
|
-
help_footer += _get_runnable_list(all_usable_commands)
|
|
670
|
-
else:
|
|
671
|
-
help_footer = f"The selected module '{import_ref.file_or_module}' has no Modal functions or classes."
|
|
672
|
-
|
|
673
|
-
raise ClickException(f"{help_header}\n\n{help_footer}")
|
|
674
|
-
|
|
675
|
-
function_spec: _FunctionSpec
|
|
676
|
-
if isinstance(runnable, MethodReference):
|
|
677
|
-
# TODO: let users specify a class instead of a method, since they use the same environment
|
|
678
|
-
class_service_function = runnable.cls._get_class_service_function()
|
|
679
|
-
function_spec = class_service_function.spec
|
|
680
|
-
elif isinstance(runnable, Function):
|
|
681
|
-
function_spec = runnable.spec
|
|
682
|
-
else:
|
|
683
|
-
raise ValueError("Referenced entity is not a Modal function or class")
|
|
684
|
-
|
|
685
|
-
start_shell = partial(
|
|
686
|
-
interactive_shell,
|
|
687
|
-
image=function_spec.image,
|
|
688
|
-
mounts=function_spec.mounts,
|
|
689
|
-
secrets=function_spec.secrets,
|
|
690
|
-
network_file_systems=function_spec.network_file_systems,
|
|
691
|
-
gpu=function_spec.gpus,
|
|
692
|
-
cloud=function_spec.cloud,
|
|
693
|
-
cpu=function_spec.cpu,
|
|
694
|
-
memory=function_spec.memory,
|
|
695
|
-
volumes=function_spec.volumes,
|
|
696
|
-
region=function_spec.scheduler_placement.regions if function_spec.scheduler_placement else None,
|
|
697
|
-
pty=pty,
|
|
698
|
-
proxy=function_spec.proxy,
|
|
699
|
-
)
|
|
700
|
-
else:
|
|
701
|
-
modal_image = Image.from_registry(image, add_python=add_python) if image else None
|
|
702
|
-
volumes = {} if volume is None else {f"/mnt/{vol}": Volume.from_name(vol) for vol in volume}
|
|
703
|
-
secrets = [] if secret is None else [Secret.from_name(s) for s in secret]
|
|
704
|
-
|
|
705
|
-
mounts = []
|
|
706
|
-
if add_local:
|
|
707
|
-
for local_path_str in add_local:
|
|
708
|
-
local_path = Path(local_path_str).expanduser().resolve()
|
|
709
|
-
remote_path = PurePosixPath(f"/mnt/{local_path.name}")
|
|
710
|
-
|
|
711
|
-
if local_path.is_dir():
|
|
712
|
-
m = _Mount._from_local_dir(local_path, remote_path=remote_path)
|
|
713
|
-
else:
|
|
714
|
-
m = _Mount._from_local_file(local_path, remote_path=remote_path)
|
|
715
|
-
mounts.append(m)
|
|
716
|
-
|
|
717
|
-
start_shell = partial(
|
|
718
|
-
interactive_shell,
|
|
719
|
-
image=modal_image,
|
|
720
|
-
mounts=mounts,
|
|
721
|
-
cpu=cpu,
|
|
722
|
-
memory=memory,
|
|
723
|
-
gpu=gpu,
|
|
724
|
-
cloud=cloud,
|
|
725
|
-
volumes=volumes,
|
|
726
|
-
secrets=secrets,
|
|
727
|
-
region=region.split(",") if region else [],
|
|
728
|
-
pty=pty,
|
|
729
|
-
)
|
|
730
|
-
|
|
731
|
-
# NB: invoking under bash makes --cmd a lot more flexible.
|
|
732
|
-
cmds = shlex.split(f'/bin/bash -c "{cmd}"')
|
|
733
|
-
start_shell(app, cmds=cmds, environment_name=env, timeout=3600)
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
# Copyright Modal Labs 2022
|
|
2
|
+
import platform
|
|
3
|
+
import shlex
|
|
4
|
+
from functools import partial
|
|
5
|
+
from pathlib import Path, PurePosixPath
|
|
6
|
+
from typing import Optional
|
|
7
|
+
|
|
8
|
+
import typer
|
|
9
|
+
from click import ClickException
|
|
10
|
+
|
|
11
|
+
from .._functions import _FunctionSpec
|
|
12
|
+
from ..app import App
|
|
13
|
+
from ..environments import ensure_env
|
|
14
|
+
from ..exception import InvalidError, NotFoundError
|
|
15
|
+
from ..functions import Function
|
|
16
|
+
from ..image import Image
|
|
17
|
+
from ..mount import _Mount
|
|
18
|
+
from ..runner import interactive_shell
|
|
19
|
+
from ..secret import Secret
|
|
20
|
+
from ..volume import Volume
|
|
21
|
+
from .import_refs import (
|
|
22
|
+
MethodReference,
|
|
23
|
+
import_and_filter,
|
|
24
|
+
parse_import_ref,
|
|
25
|
+
)
|
|
26
|
+
from .run import _get_runnable_list
|
|
27
|
+
from .utils import ENV_OPTION, is_tty
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def shell(
|
|
31
|
+
ref: Optional[str] = typer.Argument(
|
|
32
|
+
default=None,
|
|
33
|
+
help=(
|
|
34
|
+
"ID of running container or Sandbox, or path to a Python file containing an App."
|
|
35
|
+
" Can also include a Function specifier, like `module.py::func`, if the file defines multiple Functions."
|
|
36
|
+
),
|
|
37
|
+
),
|
|
38
|
+
cmd: str = typer.Option("/bin/bash", "-c", "--cmd", help="Command to run inside the Modal image."),
|
|
39
|
+
env: str = ENV_OPTION,
|
|
40
|
+
image: Optional[str] = typer.Option(
|
|
41
|
+
default=None, help="Container image tag for inside the shell (if not using REF)."
|
|
42
|
+
),
|
|
43
|
+
add_python: Optional[str] = typer.Option(default=None, help="Add Python to the image (if not using REF)."),
|
|
44
|
+
volume: Optional[list[str]] = typer.Option(
|
|
45
|
+
default=None,
|
|
46
|
+
help=(
|
|
47
|
+
"Name of a `modal.Volume` to mount inside the shell at `/mnt/{name}` (if not using REF)."
|
|
48
|
+
" Can be used multiple times."
|
|
49
|
+
),
|
|
50
|
+
),
|
|
51
|
+
add_local: Optional[list[str]] = typer.Option(
|
|
52
|
+
default=None,
|
|
53
|
+
help=(
|
|
54
|
+
"Local file or directory to mount inside the shell at `/mnt/{basename}` (if not using REF)."
|
|
55
|
+
" Can be used multiple times."
|
|
56
|
+
),
|
|
57
|
+
),
|
|
58
|
+
secret: Optional[list[str]] = typer.Option(
|
|
59
|
+
default=None,
|
|
60
|
+
help=("Name of a `modal.Secret` to mount inside the shell (if not using REF). Can be used multiple times."),
|
|
61
|
+
),
|
|
62
|
+
cpu: Optional[int] = typer.Option(default=None, help="Number of CPUs to allocate to the shell (if not using REF)."),
|
|
63
|
+
memory: Optional[int] = typer.Option(
|
|
64
|
+
default=None, help="Memory to allocate for the shell, in MiB (if not using REF)."
|
|
65
|
+
),
|
|
66
|
+
gpu: Optional[str] = typer.Option(
|
|
67
|
+
default=None,
|
|
68
|
+
help="GPUs to request for the shell, if any. Examples are `any`, `a10g`, `a100:4` (if not using REF).",
|
|
69
|
+
),
|
|
70
|
+
cloud: Optional[str] = typer.Option(
|
|
71
|
+
default=None,
|
|
72
|
+
help=(
|
|
73
|
+
"Cloud provider to run the shell on. Possible values are `aws`, `gcp`, `oci`, `auto` (if not using REF)."
|
|
74
|
+
),
|
|
75
|
+
),
|
|
76
|
+
region: Optional[str] = typer.Option(
|
|
77
|
+
default=None,
|
|
78
|
+
help=(
|
|
79
|
+
"Region(s) to run the container on. "
|
|
80
|
+
"Can be a single region or a comma-separated list to choose from (if not using REF)."
|
|
81
|
+
),
|
|
82
|
+
),
|
|
83
|
+
pty: Optional[bool] = typer.Option(default=None, help="Run the command using a PTY."),
|
|
84
|
+
use_module_mode: bool = typer.Option(
|
|
85
|
+
False, "-m", help="Interpret argument as a Python module path instead of a file/script path"
|
|
86
|
+
),
|
|
87
|
+
):
|
|
88
|
+
"""Run a command or interactive shell inside a Modal container.
|
|
89
|
+
|
|
90
|
+
**Examples:**
|
|
91
|
+
|
|
92
|
+
Start an interactive shell inside the default Debian-based image:
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
modal shell
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Start an interactive shell with the spec for `my_function` in your App
|
|
99
|
+
(uses the same image, volumes, mounts, etc.):
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
modal shell hello_world.py::my_function
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Or, if you're using a [modal.Cls](https://modal.com/docs/reference/modal.Cls)
|
|
106
|
+
you can refer to a `@modal.method` directly:
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
modal shell hello_world.py::MyClass.my_method
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Start a `python` shell:
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
modal shell hello_world.py --cmd=python
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Run a command with your function's spec and pipe the output to a file:
|
|
119
|
+
|
|
120
|
+
```
|
|
121
|
+
modal shell hello_world.py -c 'uv pip list' > env.txt
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Connect to a running Sandbox by ID:
|
|
125
|
+
|
|
126
|
+
```
|
|
127
|
+
modal shell sb-abc123xyz
|
|
128
|
+
```
|
|
129
|
+
"""
|
|
130
|
+
env = ensure_env(env)
|
|
131
|
+
|
|
132
|
+
if pty is None:
|
|
133
|
+
pty = is_tty()
|
|
134
|
+
|
|
135
|
+
if platform.system() == "Windows":
|
|
136
|
+
raise InvalidError("`modal shell` is currently not supported on Windows")
|
|
137
|
+
|
|
138
|
+
app = App("modal shell")
|
|
139
|
+
|
|
140
|
+
if ref is not None:
|
|
141
|
+
# `modal shell` with a sandbox ID gets the task_id, that's then handled by the `ta-*` flow below.
|
|
142
|
+
if ref.startswith("sb-") and len(ref[3:]) > 0 and ref[3:].isalnum():
|
|
143
|
+
from ..sandbox import Sandbox
|
|
144
|
+
|
|
145
|
+
try:
|
|
146
|
+
sandbox = Sandbox.from_id(ref)
|
|
147
|
+
task_id = sandbox._get_task_id()
|
|
148
|
+
ref = task_id
|
|
149
|
+
except NotFoundError as e:
|
|
150
|
+
raise ClickException(f"Sandbox '{ref}' not found")
|
|
151
|
+
except Exception as e:
|
|
152
|
+
raise ClickException(f"Error connecting to sandbox '{ref}': {str(e)}")
|
|
153
|
+
|
|
154
|
+
# `modal shell` with a container ID is a special case, alias for `modal container exec`.
|
|
155
|
+
if ref.startswith("ta-") and len(ref[3:]) > 0 and ref[3:].isalnum():
|
|
156
|
+
from .container import exec
|
|
157
|
+
|
|
158
|
+
exec(container_id=ref, command=shlex.split(cmd), pty=pty)
|
|
159
|
+
return
|
|
160
|
+
|
|
161
|
+
import_ref = parse_import_ref(ref, use_module_mode=use_module_mode)
|
|
162
|
+
runnable, all_usable_commands = import_and_filter(
|
|
163
|
+
import_ref, base_cmd="modal shell", accept_local_entrypoint=False, accept_webhook=True
|
|
164
|
+
)
|
|
165
|
+
if not runnable:
|
|
166
|
+
help_header = (
|
|
167
|
+
"Specify a Modal function to start a shell session for. E.g.\n"
|
|
168
|
+
f"> modal shell {import_ref.file_or_module}::my_function"
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
if all_usable_commands:
|
|
172
|
+
help_footer = f"The selected module '{import_ref.file_or_module}' has the following choices:\n\n"
|
|
173
|
+
help_footer += _get_runnable_list(all_usable_commands)
|
|
174
|
+
else:
|
|
175
|
+
help_footer = f"The selected module '{import_ref.file_or_module}' has no Modal functions or classes."
|
|
176
|
+
|
|
177
|
+
raise ClickException(f"{help_header}\n\n{help_footer}")
|
|
178
|
+
|
|
179
|
+
function_spec: _FunctionSpec
|
|
180
|
+
if isinstance(runnable, MethodReference):
|
|
181
|
+
# TODO: let users specify a class instead of a method, since they use the same environment
|
|
182
|
+
class_service_function = runnable.cls._get_class_service_function()
|
|
183
|
+
function_spec = class_service_function.spec
|
|
184
|
+
elif isinstance(runnable, Function):
|
|
185
|
+
function_spec = runnable.spec
|
|
186
|
+
else:
|
|
187
|
+
raise ValueError("Referenced entity is not a Modal function or class")
|
|
188
|
+
|
|
189
|
+
start_shell = partial(
|
|
190
|
+
interactive_shell,
|
|
191
|
+
image=function_spec.image,
|
|
192
|
+
mounts=function_spec.mounts,
|
|
193
|
+
secrets=function_spec.secrets,
|
|
194
|
+
network_file_systems=function_spec.network_file_systems,
|
|
195
|
+
gpu=function_spec.gpus,
|
|
196
|
+
cloud=function_spec.cloud,
|
|
197
|
+
cpu=function_spec.cpu,
|
|
198
|
+
memory=function_spec.memory,
|
|
199
|
+
volumes=function_spec.volumes,
|
|
200
|
+
region=function_spec.scheduler_placement.regions if function_spec.scheduler_placement else None,
|
|
201
|
+
pty=pty,
|
|
202
|
+
proxy=function_spec.proxy,
|
|
203
|
+
)
|
|
204
|
+
else:
|
|
205
|
+
modal_image = Image.from_registry(image, add_python=add_python) if image else None
|
|
206
|
+
volumes = {} if volume is None else {f"/mnt/{vol}": Volume.from_name(vol) for vol in volume}
|
|
207
|
+
secrets = [] if secret is None else [Secret.from_name(s) for s in secret]
|
|
208
|
+
|
|
209
|
+
mounts = []
|
|
210
|
+
if add_local:
|
|
211
|
+
for local_path_str in add_local:
|
|
212
|
+
local_path = Path(local_path_str).expanduser().resolve()
|
|
213
|
+
remote_path = PurePosixPath(f"/mnt/{local_path.name}")
|
|
214
|
+
|
|
215
|
+
if local_path.is_dir():
|
|
216
|
+
m = _Mount._from_local_dir(local_path, remote_path=remote_path)
|
|
217
|
+
else:
|
|
218
|
+
m = _Mount._from_local_file(local_path, remote_path=remote_path)
|
|
219
|
+
mounts.append(m)
|
|
220
|
+
|
|
221
|
+
start_shell = partial(
|
|
222
|
+
interactive_shell,
|
|
223
|
+
image=modal_image,
|
|
224
|
+
mounts=mounts,
|
|
225
|
+
cpu=cpu,
|
|
226
|
+
memory=memory,
|
|
227
|
+
gpu=gpu,
|
|
228
|
+
cloud=cloud,
|
|
229
|
+
volumes=volumes,
|
|
230
|
+
secrets=secrets,
|
|
231
|
+
region=region.split(",") if region else [],
|
|
232
|
+
pty=pty,
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
# NB: invoking under bash makes --cmd a lot more flexible.
|
|
236
|
+
cmds = shlex.split(f'/bin/bash -c "{cmd}"')
|
|
237
|
+
start_shell(app, cmds=cmds, environment_name=env, timeout=3600)
|
|
@@ -32,7 +32,7 @@ class _Client:
|
|
|
32
32
|
server_url: str,
|
|
33
33
|
client_type: int,
|
|
34
34
|
credentials: typing.Optional[tuple[str, str]],
|
|
35
|
-
version: str = "1.2.
|
|
35
|
+
version: str = "1.2.5.dev0",
|
|
36
36
|
):
|
|
37
37
|
"""mdmd:hidden
|
|
38
38
|
The Modal client object is not intended to be instantiated directly by users.
|
|
@@ -163,7 +163,7 @@ class Client:
|
|
|
163
163
|
server_url: str,
|
|
164
164
|
client_type: int,
|
|
165
165
|
credentials: typing.Optional[tuple[str, str]],
|
|
166
|
-
version: str = "1.2.
|
|
166
|
+
version: str = "1.2.5.dev0",
|
|
167
167
|
):
|
|
168
168
|
"""mdmd:hidden
|
|
169
169
|
The Modal client object is not intended to be instantiated directly by users.
|
|
@@ -408,7 +408,7 @@ class Function(
|
|
|
408
408
|
|
|
409
409
|
_call_generator: ___call_generator_spec[typing_extensions.Self]
|
|
410
410
|
|
|
411
|
-
class __remote_spec(typing_extensions.Protocol[
|
|
411
|
+
class __remote_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER, SUPERSELF]):
|
|
412
412
|
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> ReturnType_INNER:
|
|
413
413
|
"""Calls the function remotely, executing it with the given arguments and returning the execution's result."""
|
|
414
414
|
...
|
|
@@ -417,7 +417,7 @@ class Function(
|
|
|
417
417
|
"""Calls the function remotely, executing it with the given arguments and returning the execution's result."""
|
|
418
418
|
...
|
|
419
419
|
|
|
420
|
-
remote: __remote_spec[modal._functions.
|
|
420
|
+
remote: __remote_spec[modal._functions.ReturnType, modal._functions.P, typing_extensions.Self]
|
|
421
421
|
|
|
422
422
|
class __remote_gen_spec(typing_extensions.Protocol[SUPERSELF]):
|
|
423
423
|
def __call__(self, /, *args, **kwargs) -> typing.Generator[typing.Any, None, None]:
|
|
@@ -444,7 +444,7 @@ class Function(
|
|
|
444
444
|
"""
|
|
445
445
|
...
|
|
446
446
|
|
|
447
|
-
class ___experimental_spawn_spec(typing_extensions.Protocol[
|
|
447
|
+
class ___experimental_spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER, SUPERSELF]):
|
|
448
448
|
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
|
|
449
449
|
"""[Experimental] Calls the function with the given arguments, without waiting for the results.
|
|
450
450
|
|
|
@@ -468,7 +468,7 @@ class Function(
|
|
|
468
468
|
...
|
|
469
469
|
|
|
470
470
|
_experimental_spawn: ___experimental_spawn_spec[
|
|
471
|
-
modal._functions.
|
|
471
|
+
modal._functions.ReturnType, modal._functions.P, typing_extensions.Self
|
|
472
472
|
]
|
|
473
473
|
|
|
474
474
|
class ___spawn_map_inner_spec(typing_extensions.Protocol[P_INNER, SUPERSELF]):
|
|
@@ -477,7 +477,7 @@ class Function(
|
|
|
477
477
|
|
|
478
478
|
_spawn_map_inner: ___spawn_map_inner_spec[modal._functions.P, typing_extensions.Self]
|
|
479
479
|
|
|
480
|
-
class __spawn_spec(typing_extensions.Protocol[
|
|
480
|
+
class __spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER, SUPERSELF]):
|
|
481
481
|
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
|
|
482
482
|
"""Calls the function with the given arguments, without waiting for the results.
|
|
483
483
|
|
|
@@ -498,7 +498,7 @@ class Function(
|
|
|
498
498
|
"""
|
|
499
499
|
...
|
|
500
500
|
|
|
501
|
-
spawn: __spawn_spec[modal._functions.
|
|
501
|
+
spawn: __spawn_spec[modal._functions.ReturnType, modal._functions.P, typing_extensions.Self]
|
|
502
502
|
|
|
503
503
|
def get_raw_f(self) -> collections.abc.Callable[..., typing.Any]:
|
|
504
504
|
"""Return the inner Python object wrapped by this Modal Function."""
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|