modal 1.4.2.dev6__tar.gz → 1.4.2.dev7__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.4.2.dev6 → modal-1.4.2.dev7}/PKG-INFO +1 -1
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/cli/app.py +110 -26
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/cli/container.py +20 -2
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/cli/utils.py +10 -17
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/client.pyi +2 -2
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/functions.pyi +6 -6
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/image.py +2 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/image.pyi +2 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal.egg-info/PKG-INFO +1 -1
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal_proto/api_pb2.py +340 -340
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal_proto/api_pb2.pyi +12 -2
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal_version/__init__.py +1 -1
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/LICENSE +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/README.md +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/__init__.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/__main__.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_billing.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_clustered_functions.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_clustered_functions.pyi +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_container_entrypoint.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_functions.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_grpc_client.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_ipython.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_load_context.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_location.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_logs.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_object.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_output/__init__.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_output/manager.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_output/pty.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_output/rich.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_output/status.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_partial_function.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_resolver.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_resources.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_runtime/__init__.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_runtime/asgi.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_runtime/container_io_manager.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_runtime/container_io_manager.pyi +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_runtime/execution_context.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_runtime/execution_context.pyi +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_runtime/gpu_memory_snapshot.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_runtime/telemetry.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_runtime/user_code_event_loop.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_runtime/user_code_imports.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_serialization.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_server.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_traceback.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_tunnel.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_tunnel.pyi +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_type_manager.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_utils/__init__.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_utils/app_utils.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_utils/async_utils.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_utils/auth_token_manager.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_utils/blob_utils.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_utils/browser_utils.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_utils/bytes_io_segment_payload.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_utils/deprecation.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_utils/docker_utils.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_utils/function_utils.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_utils/git_utils.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_utils/grpc_testing.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_utils/grpc_utils.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_utils/hash_utils.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_utils/http_utils.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_utils/jwt_utils.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_utils/logger.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_utils/mount_utils.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_utils/name_utils.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_utils/package_utils.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_utils/pattern_utils.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_utils/rand_pb_testing.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_utils/sandbox_fs_utils.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_utils/shell_utils.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_utils/task_command_router_client.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_utils/time_utils.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_vendor/__init__.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_vendor/a2wsgi_wsgi.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_vendor/cloudpickle.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_vendor/tblib.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_vendor/version.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/_watcher.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/app.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/app.pyi +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/billing.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/builder/2023.12.312.txt +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/builder/2023.12.txt +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/builder/2024.04.txt +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/builder/2024.10.txt +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/builder/2025.06.txt +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/builder/PREVIEW.txt +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/builder/README.md +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/builder/base-images.json +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/call_graph.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/cli/__init__.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/cli/_download.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/cli/_traceback.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/cli/billing.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/cli/changelog.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/cli/cluster.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/cli/config.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/cli/dashboard.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/cli/dict.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/cli/entry_point.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/cli/environment.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/cli/import_refs.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/cli/launch.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/cli/network_file_system.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/cli/profile.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/cli/programs/__init__.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/cli/programs/run_jupyter.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/cli/programs/vscode.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/cli/queues.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/cli/run.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/cli/secret.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/cli/selector.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/cli/shell.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/cli/token.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/cli/volume.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/client.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/cloud_bucket_mount.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/cloud_bucket_mount.pyi +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/cls.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/cls.pyi +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/config.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/container_process.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/container_process.pyi +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/dict.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/dict.pyi +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/environments.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/environments.pyi +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/exception.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/experimental/__init__.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/experimental/flash.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/experimental/flash.pyi +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/experimental/ipython.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/file_io.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/file_io.pyi +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/file_pattern_matcher.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/functions.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/io_streams.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/io_streams.pyi +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/mount.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/mount.pyi +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/network_file_system.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/network_file_system.pyi +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/object.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/object.pyi +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/output.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/parallel_map.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/parallel_map.pyi +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/partial_function.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/partial_function.pyi +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/proxy.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/proxy.pyi +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/py.typed +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/queue.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/queue.pyi +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/retries.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/runner.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/runner.pyi +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/running_app.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/sandbox.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/sandbox.pyi +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/sandbox_fs.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/sandbox_fs.pyi +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/schedule.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/scheduler_placement.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/secret.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/secret.pyi +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/server.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/server.pyi +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/serving.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/serving.pyi +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/snapshot.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/snapshot.pyi +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/stream_type.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/token_flow.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/token_flow.pyi +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/volume.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal/volume.pyi +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal.egg-info/SOURCES.txt +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal.egg-info/dependency_links.txt +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal.egg-info/entry_points.txt +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal.egg-info/requires.txt +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal.egg-info/top_level.txt +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal_docs/__init__.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal_docs/gen_cli_docs.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal_docs/gen_cli_docs_main.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal_docs/gen_reference_docs.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal_docs/gen_reference_docs_main.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal_docs/mdmd/__init__.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal_docs/mdmd/mdmd.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal_docs/mdmd/signatures.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal_proto/__init__.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal_proto/api_grpc.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal_proto/api_pb2_grpc.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal_proto/api_pb2_grpc.pyi +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal_proto/modal_api_grpc.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal_proto/py.typed +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal_proto/task_command_router_grpc.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal_proto/task_command_router_pb2.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal_proto/task_command_router_pb2.pyi +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal_proto/task_command_router_pb2_grpc.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal_proto/task_command_router_pb2_grpc.pyi +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/modal_version/__main__.py +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/pyproject.toml +0 -0
- {modal-1.4.2.dev6 → modal-1.4.2.dev7}/setup.cfg +0 -0
|
@@ -20,13 +20,22 @@ from modal._utils.async_utils import synchronizer
|
|
|
20
20
|
from modal._utils.browser_utils import open_url_and_display
|
|
21
21
|
from modal.client import _Client
|
|
22
22
|
from modal.environments import ensure_env
|
|
23
|
+
from modal.exception import InvalidError, NotFoundError
|
|
23
24
|
from modal.output import OutputManager
|
|
24
25
|
from modal.runner import DEPLOYMENT_STRATEGY_TYPE, _stop_and_wait_for_containers
|
|
25
26
|
from modal_proto import api_pb2
|
|
26
27
|
|
|
27
28
|
from .._logs import _FETCH_LIMIT, _MAX_FETCH_RANGE, LogsFilters
|
|
28
29
|
from .._utils.time_utils import locale_tz, timestamp_to_localized_str
|
|
29
|
-
from .utils import
|
|
30
|
+
from .utils import (
|
|
31
|
+
ENV_OPTION,
|
|
32
|
+
YES_OPTION,
|
|
33
|
+
confirm_or_suggest_yes,
|
|
34
|
+
display_table,
|
|
35
|
+
fetch_app_logs,
|
|
36
|
+
stream_app_logs,
|
|
37
|
+
tail_app_logs,
|
|
38
|
+
)
|
|
30
39
|
|
|
31
40
|
APP_IDENTIFIER = Argument("", help="App name or ID")
|
|
32
41
|
NAME_OPTION = typer.Option("", "-n", "--name", help="Deprecated: Pass App name as a positional argument")
|
|
@@ -45,12 +54,50 @@ APP_STATE_TO_MESSAGE = {
|
|
|
45
54
|
}
|
|
46
55
|
|
|
47
56
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
57
|
+
async def resolve_app_identifier(
|
|
58
|
+
app_identifier: str, env: Optional[str], client: Optional[_Client] = None
|
|
59
|
+
) -> tuple[str, str, api_pb2.AppLifecycle]: # Return app_id, environment_name, lifecycle
|
|
60
|
+
"""Handle an App ID or an App name and return context about the App it points at.
|
|
61
|
+
|
|
62
|
+
When a name is provided, we may retrieve either a currently deployed App or an App that
|
|
63
|
+
was recently stopped (if no other App with that name has been deployed since).
|
|
64
|
+
It is up to callers of this function to decide whether it's valid to use the App ID
|
|
65
|
+
based on the lifecycle returned and their specific operations.
|
|
66
|
+
|
|
67
|
+
Can also raise a NotFoundError if the argument matches the App ID regex but the App
|
|
68
|
+
doesn't exist on the backend, or if there is no currently deployed or recently stopped App
|
|
69
|
+
with that name.
|
|
70
|
+
|
|
71
|
+
The function also always returns a valid environment name for any name-based lookups,
|
|
72
|
+
which may reflect the server-defined default environment when the provided argument was null.
|
|
73
|
+
|
|
74
|
+
"""
|
|
75
|
+
if client is None:
|
|
76
|
+
client = await _Client.from_env()
|
|
51
77
|
if re.match(r"^ap-[a-zA-Z0-9]{22}$", app_identifier):
|
|
52
|
-
return
|
|
53
|
-
|
|
78
|
+
# Identifier is an App ID. This is unambiguous, so we can make the request and return
|
|
79
|
+
# the lifecycle. AppGetLifecycle will raise NotFoundError if the ID doesn't point at an App.
|
|
80
|
+
# If we return, it's a real App, but it's up to the caller to decide what to do based on
|
|
81
|
+
# the App's current state as conveyed by the lifecycle. We do propagate a NotFoundError
|
|
82
|
+
# from the server if the App ID doesn't actually exist.
|
|
83
|
+
request = api_pb2.AppGetLifecycleRequest(app_id=app_identifier)
|
|
84
|
+
resp = await client.stub.AppGetLifecycle(request)
|
|
85
|
+
return app_identifier, "", resp.lifecycle
|
|
86
|
+
else:
|
|
87
|
+
# Identifier is treated as a name, which may or may not point at a currently deployed App
|
|
88
|
+
# (inside a specific environment)
|
|
89
|
+
request = api_pb2.AppGetByDeploymentNameRequest(name=app_identifier, environment_name=env or "")
|
|
90
|
+
resp = await client.stub.AppGetByDeploymentName(request)
|
|
91
|
+
if resp.app_id:
|
|
92
|
+
# App is currently deployed
|
|
93
|
+
return resp.app_id, resp.environment_name, resp.lifecycle
|
|
94
|
+
elif resp.previous_app_id:
|
|
95
|
+
# An App with this name was recently stopped. Return the ID of the stopped App
|
|
96
|
+
# and let callers decide what to do based on the lifecycle.
|
|
97
|
+
return resp.previous_app_id, resp.environment_name, resp.lifecycle
|
|
98
|
+
else:
|
|
99
|
+
msg = f"No App with name '{app_identifier}' found in the '{resp.environment_name}' environment."
|
|
100
|
+
raise NotFoundError(msg)
|
|
54
101
|
|
|
55
102
|
|
|
56
103
|
@app_cli.command("list")
|
|
@@ -129,7 +176,8 @@ _SOURCE_OPTIONS = {
|
|
|
129
176
|
|
|
130
177
|
|
|
131
178
|
@app_cli.command("logs", no_args_is_help=True)
|
|
132
|
-
|
|
179
|
+
@synchronizer.create_blocking
|
|
180
|
+
async def logs(
|
|
133
181
|
app_identifier: str = APP_IDENTIFIER,
|
|
134
182
|
follow: bool = typer.Option(False, "-f", "--follow", help="Stream log output until App stops"),
|
|
135
183
|
since: Optional[str] = typer.Option(
|
|
@@ -229,7 +277,7 @@ def logs(
|
|
|
229
277
|
if tail is not None and tail > _FETCH_LIMIT:
|
|
230
278
|
raise UsageError(f"--tail value must not exceed {_FETCH_LIMIT}.")
|
|
231
279
|
|
|
232
|
-
app_id =
|
|
280
|
+
app_id, _, _ = await resolve_app_identifier(app_identifier, env)
|
|
233
281
|
|
|
234
282
|
if source is not None:
|
|
235
283
|
if source not in _SOURCE_OPTIONS:
|
|
@@ -255,7 +303,7 @@ def logs(
|
|
|
255
303
|
)
|
|
256
304
|
|
|
257
305
|
if follow:
|
|
258
|
-
stream_app_logs(
|
|
306
|
+
await stream_app_logs.aio(
|
|
259
307
|
app_id,
|
|
260
308
|
task_id=container_id or "",
|
|
261
309
|
show_timestamps=timestamps,
|
|
@@ -278,7 +326,7 @@ def logs(
|
|
|
278
326
|
|
|
279
327
|
if since and tail is None:
|
|
280
328
|
# Range mode: --since without --tail fetches everything in the range.
|
|
281
|
-
fetch_app_logs(
|
|
329
|
+
await fetch_app_logs.aio(
|
|
282
330
|
app_id,
|
|
283
331
|
since_dt,
|
|
284
332
|
until_dt or now,
|
|
@@ -290,7 +338,7 @@ def logs(
|
|
|
290
338
|
# Tail mode: single fetch with limit.
|
|
291
339
|
# --since is a hard floor, --until shifts the anchor.
|
|
292
340
|
effective_tail = tail if tail is not None else _DEFAULT_LOGS_TAIL
|
|
293
|
-
tail_app_logs(
|
|
341
|
+
await tail_app_logs.aio(
|
|
294
342
|
app_id,
|
|
295
343
|
effective_tail,
|
|
296
344
|
show_timestamps=timestamps,
|
|
@@ -338,14 +386,18 @@ async def rollback(
|
|
|
338
386
|
"""
|
|
339
387
|
env = ensure_env(env)
|
|
340
388
|
client = await _Client.from_env()
|
|
341
|
-
app_id = await
|
|
389
|
+
app_id, environment_name, lifecycle = await resolve_app_identifier(app_identifier, env, client)
|
|
390
|
+
if lifecycle.app_state != api_pb2.APP_STATE_DEPLOYED:
|
|
391
|
+
env_suffix = f" in the '{environment_name}' environment" if environment_name else ""
|
|
392
|
+
raise InvalidError(f"App '{app_identifier}' is not deployed{env_suffix}.")
|
|
393
|
+
|
|
342
394
|
if not version:
|
|
343
395
|
version_number = -1
|
|
344
396
|
else:
|
|
345
397
|
if m := re.match(r"v(\d+)", version):
|
|
346
398
|
version_number = int(m.group(1))
|
|
347
399
|
else:
|
|
348
|
-
raise UsageError(f"Invalid version
|
|
400
|
+
raise UsageError(f"Invalid version specifier: {version}")
|
|
349
401
|
req = api_pb2.AppRollbackRequest(app_id=app_id, version=version_number)
|
|
350
402
|
await client.stub.AppRollback(req)
|
|
351
403
|
rich.print("[green]✓[/green] Deployment rollback successful!")
|
|
@@ -363,7 +415,7 @@ async def rollover(
|
|
|
363
415
|
),
|
|
364
416
|
env: Optional[str] = ENV_OPTION,
|
|
365
417
|
):
|
|
366
|
-
"""
|
|
418
|
+
"""Redeploy an App to get new containers without code changes.
|
|
367
419
|
|
|
368
420
|
A rollover replaces existing containers with fresh ones built from the same
|
|
369
421
|
App version — useful for refreshing containers without changing your code.
|
|
@@ -372,13 +424,13 @@ async def rollover(
|
|
|
372
424
|
**Examples:**
|
|
373
425
|
|
|
374
426
|
Rollover an App using a rolling deployment. Running containers are now considered
|
|
375
|
-
outdated and
|
|
427
|
+
outdated and will be gracefully replaced by new ones.
|
|
376
428
|
|
|
377
429
|
```
|
|
378
430
|
modal app rollover my-app
|
|
379
431
|
```
|
|
380
432
|
|
|
381
|
-
Rollover an App by
|
|
433
|
+
Rollover an App by terminating any running containers. Inputs on the queue will
|
|
382
434
|
start new containers.
|
|
383
435
|
|
|
384
436
|
```
|
|
@@ -386,13 +438,17 @@ async def rollover(
|
|
|
386
438
|
```
|
|
387
439
|
"""
|
|
388
440
|
env = ensure_env(env)
|
|
441
|
+
client = await _Client.from_env()
|
|
442
|
+
|
|
443
|
+
app_id, environment_name, lifecycle = await resolve_app_identifier(app_identifier, env, client)
|
|
444
|
+
if lifecycle.app_state != api_pb2.APP_STATE_DEPLOYED:
|
|
445
|
+
env_suffix = f" in the '{environment_name}' environment" if environment_name else ""
|
|
446
|
+
raise InvalidError(f"App '{app_identifier}' is not deployed{env_suffix}.")
|
|
447
|
+
|
|
389
448
|
output_mgr = OutputManager.get()
|
|
390
449
|
output_mgr.print(f"🔨 Starting app rollover with {strategy} strategy")
|
|
391
450
|
t0 = time.monotonic()
|
|
392
451
|
|
|
393
|
-
client = await _Client.from_env()
|
|
394
|
-
app_id = await get_app_id.aio(app_identifier, env, client)
|
|
395
|
-
|
|
396
452
|
req = api_pb2.AppRolloverRequest(app_id=app_id)
|
|
397
453
|
response = await client.stub.AppRollover(req)
|
|
398
454
|
print_server_warnings(response.server_warnings)
|
|
@@ -415,11 +471,40 @@ async def rollover(
|
|
|
415
471
|
async def stop(
|
|
416
472
|
app_identifier: str = APP_IDENTIFIER,
|
|
417
473
|
*,
|
|
474
|
+
yes: bool = YES_OPTION,
|
|
418
475
|
env: Optional[str] = ENV_OPTION,
|
|
419
476
|
):
|
|
420
|
-
"""
|
|
477
|
+
"""Permanently stop an App and terminate its running containers."""
|
|
478
|
+
env = ensure_env(env)
|
|
421
479
|
client = await _Client.from_env()
|
|
422
|
-
app_id = await
|
|
480
|
+
app_id, environment_name, lifecycle = await resolve_app_identifier(app_identifier, env, client)
|
|
481
|
+
|
|
482
|
+
if lifecycle.app_state == api_pb2.APP_STATE_STOPPED:
|
|
483
|
+
msg = "App is already stopped."
|
|
484
|
+
if lifecycle.stopped_at:
|
|
485
|
+
stopped_at = timestamp_to_localized_str(lifecycle.stopped_at)
|
|
486
|
+
verb = "Stopped" if lifecycle.stopped_by else "Finished"
|
|
487
|
+
attribution = f" by '{lifecycle.stopped_by}'" if lifecycle.stopped_by else ""
|
|
488
|
+
msg += f" ({verb} at {stopped_at}{attribution})."
|
|
489
|
+
raise SystemExit(msg)
|
|
490
|
+
|
|
491
|
+
if not yes:
|
|
492
|
+
res = await client.stub.TaskList(api_pb2.TaskListRequest(app_id=app_id))
|
|
493
|
+
num_containers = len(res.tasks)
|
|
494
|
+
|
|
495
|
+
if environment_name:
|
|
496
|
+
msg = f"Are you sure you want to stop App '{app_identifier}' in the '{environment_name}' environment?"
|
|
497
|
+
else:
|
|
498
|
+
msg = f"Are you sure you want to stop App '{app_identifier}'?"
|
|
499
|
+
|
|
500
|
+
if num_containers:
|
|
501
|
+
msg += (
|
|
502
|
+
f" This will immediately terminate {num_containers} running"
|
|
503
|
+
f" container{'s' if num_containers != 1 else ''}."
|
|
504
|
+
)
|
|
505
|
+
else:
|
|
506
|
+
msg += " No containers are currently running."
|
|
507
|
+
confirm_or_suggest_yes(msg)
|
|
423
508
|
req = api_pb2.AppStopRequest(app_id=app_id, source=api_pb2.APP_STOP_SOURCE_CLI)
|
|
424
509
|
await client.stub.AppStop(req)
|
|
425
510
|
|
|
@@ -432,7 +517,7 @@ async def history(
|
|
|
432
517
|
env: Optional[str] = ENV_OPTION,
|
|
433
518
|
json: bool = False,
|
|
434
519
|
):
|
|
435
|
-
"""Show App deployment history
|
|
520
|
+
"""Show an App's deployment history.
|
|
436
521
|
|
|
437
522
|
**Examples:**
|
|
438
523
|
|
|
@@ -442,7 +527,7 @@ async def history(
|
|
|
442
527
|
modal app history ap-123456
|
|
443
528
|
```
|
|
444
529
|
|
|
445
|
-
Get the history for
|
|
530
|
+
Get the history for an App based on its name:
|
|
446
531
|
|
|
447
532
|
```
|
|
448
533
|
modal app history my-app
|
|
@@ -451,7 +536,7 @@ async def history(
|
|
|
451
536
|
"""
|
|
452
537
|
env = ensure_env(env)
|
|
453
538
|
client = await _Client.from_env()
|
|
454
|
-
app_id = await
|
|
539
|
+
app_id, _, _ = await resolve_app_identifier(app_identifier, env, client)
|
|
455
540
|
resp = await client.stub.AppDeploymentHistory(api_pb2.AppDeploymentHistoryRequest(app_id=app_id))
|
|
456
541
|
|
|
457
542
|
columns = [
|
|
@@ -526,7 +611,6 @@ async def dashboard(
|
|
|
526
611
|
```
|
|
527
612
|
"""
|
|
528
613
|
client = await _Client.from_env()
|
|
529
|
-
app_id = await
|
|
530
|
-
|
|
614
|
+
app_id, _, _ = await resolve_app_identifier(app_identifier, env, client)
|
|
531
615
|
url = f"https://modal.com/id/{app_id}"
|
|
532
616
|
open_url_and_display(url, "App dashboard")
|
|
@@ -14,7 +14,16 @@ from modal._output.pty import get_pty_info
|
|
|
14
14
|
from modal._utils.async_utils import synchronizer
|
|
15
15
|
from modal._utils.time_utils import timestamp_to_localized_str
|
|
16
16
|
from modal.cli.app import _DEFAULT_LOGS_TAIL, _SOURCE_OPTIONS, _parse_time_arg
|
|
17
|
-
from modal.cli.utils import
|
|
17
|
+
from modal.cli.utils import (
|
|
18
|
+
ENV_OPTION,
|
|
19
|
+
YES_OPTION,
|
|
20
|
+
confirm_or_suggest_yes,
|
|
21
|
+
display_table,
|
|
22
|
+
fetch_app_logs,
|
|
23
|
+
is_tty,
|
|
24
|
+
stream_app_logs,
|
|
25
|
+
tail_app_logs,
|
|
26
|
+
)
|
|
18
27
|
from modal.client import _Client
|
|
19
28
|
from modal.config import config
|
|
20
29
|
from modal.container_process import _ContainerProcess
|
|
@@ -285,11 +294,20 @@ async def exec(
|
|
|
285
294
|
|
|
286
295
|
@container_cli.command("stop")
|
|
287
296
|
@synchronizer.create_blocking
|
|
288
|
-
async def stop(
|
|
297
|
+
async def stop(
|
|
298
|
+
container_id: str = typer.Argument(help="Container ID"),
|
|
299
|
+
*,
|
|
300
|
+
yes: bool = YES_OPTION,
|
|
301
|
+
):
|
|
289
302
|
"""Stop a currently-running container and reassign its in-progress inputs.
|
|
290
303
|
|
|
291
304
|
This will send the container a SIGINT signal that Modal will handle.
|
|
292
305
|
"""
|
|
293
306
|
client = await _Client.from_env()
|
|
307
|
+
resp = await client.stub.TaskGetInfo(api_pb2.TaskGetInfoRequest(task_id=container_id))
|
|
308
|
+
if resp.info.finished_at:
|
|
309
|
+
raise SystemExit(f"Container '{container_id}' is already stopped.")
|
|
310
|
+
if not yes:
|
|
311
|
+
confirm_or_suggest_yes(f"Are you sure you want to stop container '{container_id}'?")
|
|
294
312
|
request = api_pb2.ContainerStopRequest(task_id=container_id)
|
|
295
313
|
await client.stub.ContainerStop(request)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# Copyright Modal Labs 2022
|
|
2
2
|
import asyncio
|
|
3
3
|
import io
|
|
4
|
+
import sys
|
|
4
5
|
from collections.abc import Sequence
|
|
5
6
|
from contextlib import nullcontext
|
|
6
7
|
from csv import writer as csv_writer
|
|
@@ -12,14 +13,11 @@ import typer
|
|
|
12
13
|
from rich.table import Column, Table
|
|
13
14
|
from rich.text import Text
|
|
14
15
|
|
|
15
|
-
from modal_proto import api_pb2
|
|
16
|
-
|
|
17
16
|
from .._logs import LogsFilters, fetch_logs, tail_logs
|
|
18
17
|
from .._output.pty import _build_log_prefix, get_app_logs_loop
|
|
19
18
|
from .._utils.async_utils import synchronizer
|
|
20
19
|
from ..client import _Client
|
|
21
|
-
from ..
|
|
22
|
-
from ..exception import InvalidError, NotFoundError
|
|
20
|
+
from ..exception import InvalidError
|
|
23
21
|
from ..output import OutputManager
|
|
24
22
|
|
|
25
23
|
|
|
@@ -125,19 +123,6 @@ async def fetch_app_logs(
|
|
|
125
123
|
await _drain_batches(output_mgr, batches, prefix_fields or [], filters.search_text)
|
|
126
124
|
|
|
127
125
|
|
|
128
|
-
@synchronizer.create_blocking
|
|
129
|
-
async def get_app_id_from_name(name: str, env: Optional[str], client: Optional[_Client] = None) -> str:
|
|
130
|
-
if client is None:
|
|
131
|
-
client = await _Client.from_env()
|
|
132
|
-
env_name = ensure_env(env)
|
|
133
|
-
request = api_pb2.AppGetByDeploymentNameRequest(name=name, environment_name=env_name)
|
|
134
|
-
resp = await client.stub.AppGetByDeploymentName(request)
|
|
135
|
-
if not resp.app_id:
|
|
136
|
-
env_comment = f" in the '{env_name}' environment" if env_name else ""
|
|
137
|
-
raise NotFoundError(f"Could not find a deployed app named '{name}'{env_comment}.")
|
|
138
|
-
return resp.app_id
|
|
139
|
-
|
|
140
|
-
|
|
141
126
|
def _plain(text: Union[Text, str]) -> str:
|
|
142
127
|
return text.plain if isinstance(text, Text) else text
|
|
143
128
|
|
|
@@ -185,3 +170,11 @@ Otherwise, raises an error if the workspace has multiple environments.
|
|
|
185
170
|
ENV_OPTION = typer.Option(None, "-e", "--env", help=ENV_OPTION_HELP)
|
|
186
171
|
|
|
187
172
|
YES_OPTION = typer.Option(False, "-y", "--yes", help="Run without pausing for confirmation.")
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def confirm_or_suggest_yes(msg: str) -> None:
|
|
176
|
+
"""Prompt for confirmation, or abort with a hint to use --yes if stdin is not a TTY."""
|
|
177
|
+
if not sys.stdin.isatty():
|
|
178
|
+
typer.echo(f"{msg} [y/N]: ")
|
|
179
|
+
raise SystemExit("Aborted: no interactive terminal detected. Rerun with --yes (-y) to skip confirmation.")
|
|
180
|
+
typer.confirm(msg, default=False, abort=True)
|
|
@@ -35,7 +35,7 @@ class _Client:
|
|
|
35
35
|
server_url: str,
|
|
36
36
|
client_type: int,
|
|
37
37
|
credentials: typing.Optional[tuple[str, str]],
|
|
38
|
-
version: str = "1.4.2.
|
|
38
|
+
version: str = "1.4.2.dev7",
|
|
39
39
|
):
|
|
40
40
|
"""mdmd:hidden
|
|
41
41
|
The Modal client object is not intended to be instantiated directly by users.
|
|
@@ -171,7 +171,7 @@ class Client:
|
|
|
171
171
|
server_url: str,
|
|
172
172
|
client_type: int,
|
|
173
173
|
credentials: typing.Optional[tuple[str, str]],
|
|
174
|
-
version: str = "1.4.2.
|
|
174
|
+
version: str = "1.4.2.dev7",
|
|
175
175
|
):
|
|
176
176
|
"""mdmd:hidden
|
|
177
177
|
The Modal client object is not intended to be instantiated directly by users.
|
|
@@ -348,7 +348,7 @@ class Function(
|
|
|
348
348
|
|
|
349
349
|
_call_generator: ___call_generator_spec
|
|
350
350
|
|
|
351
|
-
class __remote_spec(typing_extensions.Protocol[
|
|
351
|
+
class __remote_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER]):
|
|
352
352
|
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> ReturnType_INNER:
|
|
353
353
|
"""Calls the function remotely, executing it with the given arguments and returning the execution's result."""
|
|
354
354
|
...
|
|
@@ -357,7 +357,7 @@ class Function(
|
|
|
357
357
|
"""Calls the function remotely, executing it with the given arguments and returning the execution's result."""
|
|
358
358
|
...
|
|
359
359
|
|
|
360
|
-
remote: __remote_spec[modal._functions.
|
|
360
|
+
remote: __remote_spec[modal._functions.P, modal._functions.ReturnType]
|
|
361
361
|
|
|
362
362
|
class __remote_gen_spec(typing_extensions.Protocol):
|
|
363
363
|
def __call__(self, /, *args, **kwargs) -> typing.Generator[typing.Any, None, None]:
|
|
@@ -384,7 +384,7 @@ class Function(
|
|
|
384
384
|
"""
|
|
385
385
|
...
|
|
386
386
|
|
|
387
|
-
class ___experimental_spawn_spec(typing_extensions.Protocol[
|
|
387
|
+
class ___experimental_spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER]):
|
|
388
388
|
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
|
|
389
389
|
"""[Experimental] Calls the function with the given arguments, without waiting for the results.
|
|
390
390
|
|
|
@@ -407,7 +407,7 @@ class Function(
|
|
|
407
407
|
"""
|
|
408
408
|
...
|
|
409
409
|
|
|
410
|
-
_experimental_spawn: ___experimental_spawn_spec[modal._functions.
|
|
410
|
+
_experimental_spawn: ___experimental_spawn_spec[modal._functions.P, modal._functions.ReturnType]
|
|
411
411
|
|
|
412
412
|
class ___spawn_map_inner_spec(typing_extensions.Protocol[P_INNER]):
|
|
413
413
|
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> None: ...
|
|
@@ -415,7 +415,7 @@ class Function(
|
|
|
415
415
|
|
|
416
416
|
_spawn_map_inner: ___spawn_map_inner_spec[modal._functions.P]
|
|
417
417
|
|
|
418
|
-
class __spawn_spec(typing_extensions.Protocol[
|
|
418
|
+
class __spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER]):
|
|
419
419
|
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
|
|
420
420
|
"""Calls the function with the given arguments, without waiting for the results.
|
|
421
421
|
|
|
@@ -436,7 +436,7 @@ class Function(
|
|
|
436
436
|
"""
|
|
437
437
|
...
|
|
438
438
|
|
|
439
|
-
spawn: __spawn_spec[modal._functions.
|
|
439
|
+
spawn: __spawn_spec[modal._functions.P, modal._functions.ReturnType]
|
|
440
440
|
|
|
441
441
|
def get_raw_f(self) -> collections.abc.Callable[..., typing.Any]:
|
|
442
442
|
"""Return the inner Python object wrapped by this Modal Function."""
|
|
@@ -1644,6 +1644,7 @@ class _Image(_Object, type_prefix="im"):
|
|
|
1644
1644
|
context_dir: Optional[Union[Path, str]] = None, # Context for relative COPY commands
|
|
1645
1645
|
force_build: bool = False, # Ignore cached builds, similar to 'docker build --no-cache'
|
|
1646
1646
|
ignore: Union[Sequence[str], Callable[[Path], bool]] = AUTO_DOCKERIGNORE,
|
|
1647
|
+
build_args: dict[str, str] = {}, # Dockerfile variables to set
|
|
1647
1648
|
) -> "_Image":
|
|
1648
1649
|
"""
|
|
1649
1650
|
Extend an image with arbitrary Dockerfile-like commands.
|
|
@@ -1706,6 +1707,7 @@ class _Image(_Object, type_prefix="im"):
|
|
|
1706
1707
|
ignore=ignore, dockerfile_cmds=cmds, context_dir=context_dir
|
|
1707
1708
|
),
|
|
1708
1709
|
force_build=self.force_build or force_build,
|
|
1710
|
+
build_args=build_args,
|
|
1709
1711
|
)
|
|
1710
1712
|
|
|
1711
1713
|
def entrypoint(
|
|
@@ -623,6 +623,7 @@ class _Image(modal._object._Object):
|
|
|
623
623
|
ignore: typing.Union[
|
|
624
624
|
collections.abc.Sequence[str], collections.abc.Callable[[pathlib.Path], bool]
|
|
625
625
|
] = modal.image.AUTO_DOCKERIGNORE,
|
|
626
|
+
build_args: dict[str, str] = {},
|
|
626
627
|
) -> _Image:
|
|
627
628
|
"""Extend an image with arbitrary Dockerfile-like commands.
|
|
628
629
|
|
|
@@ -1619,6 +1620,7 @@ class Image(modal.object.Object):
|
|
|
1619
1620
|
ignore: typing.Union[
|
|
1620
1621
|
collections.abc.Sequence[str], collections.abc.Callable[[pathlib.Path], bool]
|
|
1621
1622
|
] = modal.image.AUTO_DOCKERIGNORE,
|
|
1623
|
+
build_args: dict[str, str] = {},
|
|
1622
1624
|
) -> Image:
|
|
1623
1625
|
"""Extend an image with arbitrary Dockerfile-like commands.
|
|
1624
1626
|
|