modal 1.5.6.dev9__tar.gz → 1.5.6.dev10__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.5.6.dev9 → modal-1.5.6.dev10}/PKG-INFO +1 -1
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/client.pyi +2 -2
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/sandbox.py +152 -22
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/sandbox.pyi +263 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal.egg-info/PKG-INFO +1 -1
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal_version/__init__.py +1 -1
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/LICENSE +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/README.md +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/__init__.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/__main__.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_billing.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_clustered_functions.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_clustered_functions.pyi +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_container_entrypoint.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_environments.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_function_variants.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_functions.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_grpc_client.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_image.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_ipython.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_load_context.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_location.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_logs.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_logs_manager.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_logs_manager.pyi +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_object.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_output/__init__.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_output/manager.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_output/pty.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_output/rich.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_output/status.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_partial_function.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_resolver.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_resources.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_runtime/__init__.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_runtime/asgi.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_runtime/container_io_manager.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_runtime/container_io_manager.pyi +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_runtime/execution_context.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_runtime/execution_context.pyi +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_runtime/gpu_memory_snapshot.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_runtime/task_lifecycle_manager.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_runtime/task_lifecycle_manager.pyi +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_runtime/telemetry.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_runtime/user_code_event_loop.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_runtime/user_code_imports.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_serialization.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_server.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_supports_logs.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_traceback.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_tunnel.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_tunnel.pyi +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_type_manager.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_utils/__init__.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_utils/app_utils.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_utils/async_utils.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_utils/auth_token_manager.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_utils/blob_utils.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_utils/browser_utils.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_utils/bytes_io_segment_payload.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_utils/curl_utils.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_utils/deprecation.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_utils/display_utils.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_utils/docker_utils.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_utils/function_utils.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_utils/git_utils.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_utils/grpc_testing.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_utils/grpc_utils.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_utils/hash_utils.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_utils/http_utils.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_utils/jwt_utils.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_utils/logger.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_utils/mount_utils.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_utils/name_utils.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_utils/package_utils.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_utils/pattern_utils.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_utils/proxy_support.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_utils/rand_pb_testing.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_utils/sandbox_fs_utils.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_utils/shell_utils.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_utils/task_command_router_client.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_utils/time_utils.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_vendor/__init__.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_vendor/a2wsgi_wsgi.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_vendor/cloudpickle.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_vendor/tblib.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_vendor/version.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_watcher.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/_workspace.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/app.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/app.pyi +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/billing.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/billing.pyi +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/builder/2023.12.312.txt +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/builder/2023.12.txt +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/builder/2024.04.txt +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/builder/2024.10.txt +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/builder/2025.06.txt +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/builder/PREVIEW.txt +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/builder/README.md +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/builder/base-images.json +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/call_graph.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/cli/__init__.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/cli/_download.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/cli/_help.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/cli/_traceback.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/cli/app.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/cli/billing.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/cli/bootstrap.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/cli/changelog.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/cli/cluster.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/cli/config.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/cli/container.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/cli/curl.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/cli/dashboard.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/cli/dict.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/cli/endpoint.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/cli/entry_point.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/cli/environment.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/cli/image.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/cli/import_refs.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/cli/launch.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/cli/logo.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/cli/network_file_system.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/cli/profile.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/cli/programs/__init__.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/cli/programs/run_jupyter.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/cli/programs/vscode.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/cli/queues.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/cli/run.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/cli/secret.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/cli/selector.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/cli/shell.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/cli/skills.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/cli/token.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/cli/utils.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/cli/volume.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/cli/workspace.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/client.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/cloud_bucket_mount.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/cloud_bucket_mount.pyi +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/cls.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/cls.pyi +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/config.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/container_process.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/container_process.pyi +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/dict.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/dict.pyi +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/environments.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/environments.pyi +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/exception.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/experimental/__init__.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/experimental/flash.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/experimental/flash.pyi +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/experimental/ipython.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/file_io.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/file_io.pyi +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/file_pattern_matcher.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/functions.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/functions.pyi +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/image.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/image.pyi +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/io_streams.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/io_streams.pyi +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/mount.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/mount.pyi +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/network_file_system.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/network_file_system.pyi +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/object.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/object.pyi +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/output.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/parallel_map.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/parallel_map.pyi +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/partial_function.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/partial_function.pyi +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/proxy.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/proxy.pyi +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/py.typed +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/queue.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/queue.pyi +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/retries.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/runner.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/runner.pyi +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/running_app.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/sandbox_fs.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/sandbox_fs.pyi +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/schedule.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/scheduler_placement.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/secret.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/secret.pyi +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/server.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/server.pyi +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/serving.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/serving.pyi +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/skills/modal/SKILL.md +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/snapshot.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/snapshot.pyi +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/stream_type.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/token_flow.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/token_flow.pyi +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/types.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/volume.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/volume.pyi +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/workspace.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal/workspace.pyi +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal.egg-info/SOURCES.txt +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal.egg-info/dependency_links.txt +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal.egg-info/entry_points.txt +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal.egg-info/requires.txt +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal.egg-info/top_level.txt +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal_docs/__init__.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal_docs/gen_cli_docs.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal_docs/gen_cli_docs_main.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal_docs/gen_reference_docs.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal_docs/gen_reference_docs_main.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal_docs/mdmd/__init__.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal_docs/mdmd/mdmd.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal_docs/mdmd/signatures.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal_docs/mdmd/types.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal_docs/reference_intro.md +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal_proto/__init__.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal_proto/api_grpc.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal_proto/api_pb2.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal_proto/api_pb2.pyi +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal_proto/api_pb2_grpc.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal_proto/api_pb2_grpc.pyi +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal_proto/modal_api_grpc.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal_proto/py.typed +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal_proto/task_command_router_grpc.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal_proto/task_command_router_pb2.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal_proto/task_command_router_pb2.pyi +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal_proto/task_command_router_pb2_grpc.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal_proto/task_command_router_pb2_grpc.pyi +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/modal_version/__main__.py +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/pyproject.toml +0 -0
- {modal-1.5.6.dev9 → modal-1.5.6.dev10}/setup.cfg +0 -0
|
@@ -77,7 +77,7 @@ class _Client:
|
|
|
77
77
|
server_url: str,
|
|
78
78
|
client_type: int,
|
|
79
79
|
credentials: typing.Optional[tuple[str, str]],
|
|
80
|
-
version: str = "1.5.6.
|
|
80
|
+
version: str = "1.5.6.dev10",
|
|
81
81
|
*,
|
|
82
82
|
oauth_credentials: typing.Optional[_OAuthCredentials] = None,
|
|
83
83
|
):
|
|
@@ -277,7 +277,7 @@ class Client:
|
|
|
277
277
|
server_url: str,
|
|
278
278
|
client_type: int,
|
|
279
279
|
credentials: typing.Optional[tuple[str, str]],
|
|
280
|
-
version: str = "1.5.6.
|
|
280
|
+
version: str = "1.5.6.dev10",
|
|
281
281
|
*,
|
|
282
282
|
oauth_credentials: typing.Optional[_OAuthCredentials] = None,
|
|
283
283
|
):
|
|
@@ -196,6 +196,30 @@ def _validate_experimental_encryption_key(key: bytes | None) -> bytes | None:
|
|
|
196
196
|
return key
|
|
197
197
|
|
|
198
198
|
|
|
199
|
+
def _image_id_for_mount(image: _Image, method_name: str) -> str:
|
|
200
|
+
if not isinstance(image, _Image):
|
|
201
|
+
raise TypeError(f"{method_name}(image=...) expects an Image object, got {image!r}")
|
|
202
|
+
|
|
203
|
+
if image._mount_layers:
|
|
204
|
+
raise InvalidError(
|
|
205
|
+
f"{method_name}() only supports pre-built images. When using `add_local*` methods, "
|
|
206
|
+
"specify `copy=True` and call `.build()` before passing the image to `mount_image()`:\n\nE.g.\n"
|
|
207
|
+
'img = modal.Image.debian_slim().add_local_file("foo", "/foo", copy=True).build(app)\n'
|
|
208
|
+
f"{method_name}(path, img)"
|
|
209
|
+
)
|
|
210
|
+
if image._is_empty:
|
|
211
|
+
return ""
|
|
212
|
+
if image._object_id:
|
|
213
|
+
return image._object_id
|
|
214
|
+
raise InvalidError(
|
|
215
|
+
f"{method_name}() currently only supports Images that are either:\n"
|
|
216
|
+
"- prebuilt using `image.build()`\n"
|
|
217
|
+
"- referenced by id, e.g. `Image.from_id()`\n"
|
|
218
|
+
"- filesystem/directory snapshots e.g. created by `.snapshot_directory()` "
|
|
219
|
+
"or `.snapshot_filesystem()`\n"
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
|
|
199
223
|
if TYPE_CHECKING:
|
|
200
224
|
import modal.app
|
|
201
225
|
|
|
@@ -1651,28 +1675,7 @@ class _Sandbox(_Object, type_prefix="sb"):
|
|
|
1651
1675
|
sandbox_session_2.filesystem.list_files("/user_project")
|
|
1652
1676
|
```
|
|
1653
1677
|
"""
|
|
1654
|
-
|
|
1655
|
-
raise TypeError(f"Sandbox.mount_image(image=...) expects an Image object, got {image!r}")
|
|
1656
|
-
|
|
1657
|
-
if image._mount_layers:
|
|
1658
|
-
raise InvalidError(
|
|
1659
|
-
"Sandbox.mount_image() only supports pre-built images. When using `add_local*` methods, "
|
|
1660
|
-
"specify `copy=True` and call `.build()` before passing the image to `mount_image()`:\n\nE.g.\n"
|
|
1661
|
-
'img = modal.Image.debian_slim().add_local_file("foo", "/foo", copy=True).build(app)\n'
|
|
1662
|
-
"sandbox.mount_image(path, img)"
|
|
1663
|
-
)
|
|
1664
|
-
if image._is_empty:
|
|
1665
|
-
image_id = ""
|
|
1666
|
-
elif image._object_id:
|
|
1667
|
-
image_id = image._object_id
|
|
1668
|
-
else:
|
|
1669
|
-
raise InvalidError(
|
|
1670
|
-
"Sandbox.mount_image() currently only supports Images that are either:\n"
|
|
1671
|
-
"- prebuilt using `image.build()`\n"
|
|
1672
|
-
"- referenced by id, e.g. `Image.from_id()`\n"
|
|
1673
|
-
"- filesystem/directory snapshots e.g. created by `.snapshot_directory()` "
|
|
1674
|
-
"or `.snapshot_filesystem()`\n"
|
|
1675
|
-
)
|
|
1678
|
+
image_id = _image_id_for_mount(image, "Sandbox.mount_image")
|
|
1676
1679
|
|
|
1677
1680
|
task_id = await self._get_task_id()
|
|
1678
1681
|
command_router_client = await self._get_command_router_client(task_id)
|
|
@@ -2867,6 +2870,133 @@ class _SidecarContainer:
|
|
|
2867
2870
|
self._filesystem = _SandboxFilesystem(self)
|
|
2868
2871
|
return self._filesystem
|
|
2869
2872
|
|
|
2873
|
+
async def mount_image(
|
|
2874
|
+
self,
|
|
2875
|
+
path: PurePosixPath | str,
|
|
2876
|
+
image: _Image,
|
|
2877
|
+
*,
|
|
2878
|
+
_experimental_encryption_key: bytes | None = None,
|
|
2879
|
+
) -> None:
|
|
2880
|
+
"""Mount an Image at a specified path in this Sidecar container.
|
|
2881
|
+
|
|
2882
|
+
`path` should be a directory that is **not** the root path (`/`). If the path doesn't exist,
|
|
2883
|
+
it will be created. If it exists and contains data, the previous directory will be replaced
|
|
2884
|
+
by the mount.
|
|
2885
|
+
|
|
2886
|
+
The `image` argument supports any Image that has an object ID, including:
|
|
2887
|
+
- Images built using `image.build()`
|
|
2888
|
+
- Images referenced by ID, e.g. `Image.from_id(...)`
|
|
2889
|
+
- Filesystem/directory snapshots, e.g. created by `.snapshot_directory()` or `.snapshot_filesystem()`
|
|
2890
|
+
- Empty images created with `Image.from_scratch()`
|
|
2891
|
+
|
|
2892
|
+
Args:
|
|
2893
|
+
path: Absolute mount point directory inside the Sidecar container (not `/`).
|
|
2894
|
+
image: Image to mount at `path` (must be built, referenced by ID, or snapshot-based as described above).
|
|
2895
|
+
|
|
2896
|
+
Examples:
|
|
2897
|
+
```py notest
|
|
2898
|
+
sidecar_1.mount_image("/workspace", modal.Image.from_scratch())
|
|
2899
|
+
workspace_snapshot = sidecar_1.snapshot_directory("/workspace")
|
|
2900
|
+
|
|
2901
|
+
# You can later mount this snapshot in another Sidecar:
|
|
2902
|
+
sidecar_2.mount_image("/workspace", workspace_snapshot)
|
|
2903
|
+
sidecar_2.filesystem.list_files("/workspace")
|
|
2904
|
+
```
|
|
2905
|
+
"""
|
|
2906
|
+
image_id = _image_id_for_mount(image, "SidecarContainer.mount_image")
|
|
2907
|
+
|
|
2908
|
+
posix_path = PurePosixPath(path)
|
|
2909
|
+
if not posix_path.is_absolute():
|
|
2910
|
+
raise InvalidError(f"Mount path must be absolute; got: {posix_path}")
|
|
2911
|
+
|
|
2912
|
+
task_id, command_router_client = await self._get_command_router()
|
|
2913
|
+
await command_router_client.mount_image(
|
|
2914
|
+
sr_pb2.TaskMountDirectoryRequest(
|
|
2915
|
+
task_id=task_id,
|
|
2916
|
+
path=posix_path.as_posix().encode("utf8"),
|
|
2917
|
+
image_id=image_id,
|
|
2918
|
+
customer_supplied_encryption_key=_validate_experimental_encryption_key(_experimental_encryption_key),
|
|
2919
|
+
container_id=self._container_id,
|
|
2920
|
+
)
|
|
2921
|
+
)
|
|
2922
|
+
|
|
2923
|
+
async def unmount_image(self, path: PurePosixPath | str) -> None:
|
|
2924
|
+
"""Unmount a previously mounted Image from this Sidecar container.
|
|
2925
|
+
|
|
2926
|
+
`path` must be the exact mount point that was passed to `.mount_image()`.
|
|
2927
|
+
After unmounting, the underlying Sidecar filesystem at that path becomes
|
|
2928
|
+
visible again.
|
|
2929
|
+
|
|
2930
|
+
Args:
|
|
2931
|
+
path: Absolute mount point directory to unmount.
|
|
2932
|
+
|
|
2933
|
+
"""
|
|
2934
|
+
posix_path = PurePosixPath(path)
|
|
2935
|
+
if not posix_path.is_absolute():
|
|
2936
|
+
raise InvalidError(f"Unmount path must be absolute; got: {posix_path}")
|
|
2937
|
+
|
|
2938
|
+
task_id, command_router_client = await self._get_command_router()
|
|
2939
|
+
await command_router_client.unmount_image(
|
|
2940
|
+
sr_pb2.TaskUnmountDirectoryRequest(
|
|
2941
|
+
task_id=task_id,
|
|
2942
|
+
path=posix_path.as_posix().encode("utf8"),
|
|
2943
|
+
container_id=self._container_id,
|
|
2944
|
+
)
|
|
2945
|
+
)
|
|
2946
|
+
|
|
2947
|
+
async def snapshot_directory(
|
|
2948
|
+
self,
|
|
2949
|
+
path: PurePosixPath | str,
|
|
2950
|
+
*,
|
|
2951
|
+
timeout: int = 55,
|
|
2952
|
+
ttl: int | None = 30 * 24 * 3600,
|
|
2953
|
+
_experimental_encryption_key: bytes | None = None,
|
|
2954
|
+
) -> _Image:
|
|
2955
|
+
"""Snapshot a directory in this Sidecar container, creating a new Image with its content.
|
|
2956
|
+
|
|
2957
|
+
`timeout` If the snapshot does not return within that window, the call is cancelled
|
|
2958
|
+
and `modal.exception.TimeoutError` is raised.
|
|
2959
|
+
|
|
2960
|
+
`ttl` The resulting Image is retained for `ttl` seconds (default: 30 days).
|
|
2961
|
+
Pass `ttl=None` to retain the Image indefinitely.
|
|
2962
|
+
|
|
2963
|
+
The returned Image can be used anywhere an Image is accepted, including
|
|
2964
|
+
as a mount or as the base filesystem for another container.
|
|
2965
|
+
|
|
2966
|
+
Args:
|
|
2967
|
+
path: Absolute path of the directory inside the Sidecar container to snapshot.
|
|
2968
|
+
|
|
2969
|
+
Returns:
|
|
2970
|
+
An `Image` containing the directory contents.
|
|
2971
|
+
|
|
2972
|
+
Examples:
|
|
2973
|
+
```py notest
|
|
2974
|
+
workspace_snapshot = sidecar_1.snapshot_directory("/workspace")
|
|
2975
|
+
|
|
2976
|
+
# You can later mount this snapshot in another Sidecar:
|
|
2977
|
+
sidecar_2.mount_image("/workspace", workspace_snapshot)
|
|
2978
|
+
sidecar_2.filesystem.list_files("/workspace")
|
|
2979
|
+
```
|
|
2980
|
+
"""
|
|
2981
|
+
wire_ttl_seconds = _ttl_to_wire_ttl(ttl)
|
|
2982
|
+
posix_path = PurePosixPath(path)
|
|
2983
|
+
if not posix_path.is_absolute():
|
|
2984
|
+
raise InvalidError(f"Snapshot path must be absolute; got: {posix_path}")
|
|
2985
|
+
|
|
2986
|
+
task_id, command_router_client = await self._get_command_router()
|
|
2987
|
+
response = await command_router_client.snapshot_directory(
|
|
2988
|
+
sr_pb2.TaskSnapshotDirectoryRequest(
|
|
2989
|
+
task_id=task_id,
|
|
2990
|
+
path=posix_path.as_posix().encode("utf8"),
|
|
2991
|
+
snapshot_id=str(uuid.uuid4()),
|
|
2992
|
+
ttl_seconds=wire_ttl_seconds,
|
|
2993
|
+
customer_supplied_encryption_key=_validate_experimental_encryption_key(_experimental_encryption_key),
|
|
2994
|
+
container_id=self._container_id,
|
|
2995
|
+
),
|
|
2996
|
+
timeout=float(timeout),
|
|
2997
|
+
)
|
|
2998
|
+
return _Image._new_hydrated(response.image_id, self._sandbox._client, None)
|
|
2999
|
+
|
|
2870
3000
|
async def wait(self, raise_on_termination: bool = True) -> None:
|
|
2871
3001
|
if self._result is not None and self._result.status != api_pb2.GenericResult.GENERIC_STATUS_UNSPECIFIED:
|
|
2872
3002
|
if self._result.status == api_pb2.GenericResult.GENERIC_STATUS_TERMINATED and raise_on_termination:
|
|
@@ -50,6 +50,7 @@ def _ttl_to_wire_ttl(ttl: typing.Optional[int]) -> int:
|
|
|
50
50
|
...
|
|
51
51
|
|
|
52
52
|
def _validate_experimental_encryption_key(key: typing.Optional[bytes]) -> typing.Optional[bytes]: ...
|
|
53
|
+
def _image_id_for_mount(image: modal._image._Image, method_name: str) -> str: ...
|
|
53
54
|
|
|
54
55
|
class SandboxVersion(enum.Enum):
|
|
55
56
|
V1 = 1
|
|
@@ -1171,6 +1172,89 @@ class _SidecarContainer:
|
|
|
1171
1172
|
"""Namespace for Sandbox filesystem APIs."""
|
|
1172
1173
|
...
|
|
1173
1174
|
|
|
1175
|
+
async def mount_image(
|
|
1176
|
+
self,
|
|
1177
|
+
path: typing.Union[pathlib.PurePosixPath, str],
|
|
1178
|
+
image: modal._image._Image,
|
|
1179
|
+
*,
|
|
1180
|
+
_experimental_encryption_key: typing.Optional[bytes] = None,
|
|
1181
|
+
) -> None:
|
|
1182
|
+
"""Mount an Image at a specified path in this Sidecar container.
|
|
1183
|
+
|
|
1184
|
+
`path` should be a directory that is **not** the root path (`/`). If the path doesn't exist,
|
|
1185
|
+
it will be created. If it exists and contains data, the previous directory will be replaced
|
|
1186
|
+
by the mount.
|
|
1187
|
+
|
|
1188
|
+
The `image` argument supports any Image that has an object ID, including:
|
|
1189
|
+
- Images built using `image.build()`
|
|
1190
|
+
- Images referenced by ID, e.g. `Image.from_id(...)`
|
|
1191
|
+
- Filesystem/directory snapshots, e.g. created by `.snapshot_directory()` or `.snapshot_filesystem()`
|
|
1192
|
+
- Empty images created with `Image.from_scratch()`
|
|
1193
|
+
|
|
1194
|
+
Args:
|
|
1195
|
+
path: Absolute mount point directory inside the Sidecar container (not `/`).
|
|
1196
|
+
image: Image to mount at `path` (must be built, referenced by ID, or snapshot-based as described above).
|
|
1197
|
+
|
|
1198
|
+
Examples:
|
|
1199
|
+
```py notest
|
|
1200
|
+
sidecar_1.mount_image("/workspace", modal.Image.from_scratch())
|
|
1201
|
+
workspace_snapshot = sidecar_1.snapshot_directory("/workspace")
|
|
1202
|
+
|
|
1203
|
+
# You can later mount this snapshot in another Sidecar:
|
|
1204
|
+
sidecar_2.mount_image("/workspace", workspace_snapshot)
|
|
1205
|
+
sidecar_2.filesystem.list_files("/workspace")
|
|
1206
|
+
```
|
|
1207
|
+
"""
|
|
1208
|
+
...
|
|
1209
|
+
|
|
1210
|
+
async def unmount_image(self, path: typing.Union[pathlib.PurePosixPath, str]) -> None:
|
|
1211
|
+
"""Unmount a previously mounted Image from this Sidecar container.
|
|
1212
|
+
|
|
1213
|
+
`path` must be the exact mount point that was passed to `.mount_image()`.
|
|
1214
|
+
After unmounting, the underlying Sidecar filesystem at that path becomes
|
|
1215
|
+
visible again.
|
|
1216
|
+
|
|
1217
|
+
Args:
|
|
1218
|
+
path: Absolute mount point directory to unmount.
|
|
1219
|
+
"""
|
|
1220
|
+
...
|
|
1221
|
+
|
|
1222
|
+
async def snapshot_directory(
|
|
1223
|
+
self,
|
|
1224
|
+
path: typing.Union[pathlib.PurePosixPath, str],
|
|
1225
|
+
*,
|
|
1226
|
+
timeout: int = 55,
|
|
1227
|
+
ttl: typing.Optional[int] = 2592000,
|
|
1228
|
+
_experimental_encryption_key: typing.Optional[bytes] = None,
|
|
1229
|
+
) -> modal._image._Image:
|
|
1230
|
+
"""Snapshot a directory in this Sidecar container, creating a new Image with its content.
|
|
1231
|
+
|
|
1232
|
+
`timeout` If the snapshot does not return within that window, the call is cancelled
|
|
1233
|
+
and `modal.exception.TimeoutError` is raised.
|
|
1234
|
+
|
|
1235
|
+
`ttl` The resulting Image is retained for `ttl` seconds (default: 30 days).
|
|
1236
|
+
Pass `ttl=None` to retain the Image indefinitely.
|
|
1237
|
+
|
|
1238
|
+
The returned Image can be used anywhere an Image is accepted, including
|
|
1239
|
+
as a mount or as the base filesystem for another container.
|
|
1240
|
+
|
|
1241
|
+
Args:
|
|
1242
|
+
path: Absolute path of the directory inside the Sidecar container to snapshot.
|
|
1243
|
+
|
|
1244
|
+
Returns:
|
|
1245
|
+
An `Image` containing the directory contents.
|
|
1246
|
+
|
|
1247
|
+
Examples:
|
|
1248
|
+
```py notest
|
|
1249
|
+
workspace_snapshot = sidecar_1.snapshot_directory("/workspace")
|
|
1250
|
+
|
|
1251
|
+
# You can later mount this snapshot in another Sidecar:
|
|
1252
|
+
sidecar_2.mount_image("/workspace", workspace_snapshot)
|
|
1253
|
+
sidecar_2.filesystem.list_files("/workspace")
|
|
1254
|
+
```
|
|
1255
|
+
"""
|
|
1256
|
+
...
|
|
1257
|
+
|
|
1174
1258
|
async def wait(self, raise_on_termination: bool = True) -> None: ...
|
|
1175
1259
|
async def poll(self) -> typing.Optional[int]: ...
|
|
1176
1260
|
@typing.overload
|
|
@@ -1420,6 +1504,185 @@ class SidecarContainer:
|
|
|
1420
1504
|
"""Namespace for Sandbox filesystem APIs."""
|
|
1421
1505
|
...
|
|
1422
1506
|
|
|
1507
|
+
class __mount_image_spec(typing_extensions.Protocol):
|
|
1508
|
+
def __call__(
|
|
1509
|
+
self,
|
|
1510
|
+
/,
|
|
1511
|
+
path: typing.Union[pathlib.PurePosixPath, str],
|
|
1512
|
+
image: modal.image.Image,
|
|
1513
|
+
*,
|
|
1514
|
+
_experimental_encryption_key: typing.Optional[bytes] = None,
|
|
1515
|
+
) -> None:
|
|
1516
|
+
"""Mount an Image at a specified path in this Sidecar container.
|
|
1517
|
+
|
|
1518
|
+
`path` should be a directory that is **not** the root path (`/`). If the path doesn't exist,
|
|
1519
|
+
it will be created. If it exists and contains data, the previous directory will be replaced
|
|
1520
|
+
by the mount.
|
|
1521
|
+
|
|
1522
|
+
The `image` argument supports any Image that has an object ID, including:
|
|
1523
|
+
- Images built using `image.build()`
|
|
1524
|
+
- Images referenced by ID, e.g. `Image.from_id(...)`
|
|
1525
|
+
- Filesystem/directory snapshots, e.g. created by `.snapshot_directory()` or `.snapshot_filesystem()`
|
|
1526
|
+
- Empty images created with `Image.from_scratch()`
|
|
1527
|
+
|
|
1528
|
+
Args:
|
|
1529
|
+
path: Absolute mount point directory inside the Sidecar container (not `/`).
|
|
1530
|
+
image: Image to mount at `path` (must be built, referenced by ID, or snapshot-based as described above).
|
|
1531
|
+
|
|
1532
|
+
Examples:
|
|
1533
|
+
```py notest
|
|
1534
|
+
sidecar_1.mount_image("/workspace", modal.Image.from_scratch())
|
|
1535
|
+
workspace_snapshot = sidecar_1.snapshot_directory("/workspace")
|
|
1536
|
+
|
|
1537
|
+
# You can later mount this snapshot in another Sidecar:
|
|
1538
|
+
sidecar_2.mount_image("/workspace", workspace_snapshot)
|
|
1539
|
+
sidecar_2.filesystem.list_files("/workspace")
|
|
1540
|
+
```
|
|
1541
|
+
"""
|
|
1542
|
+
...
|
|
1543
|
+
|
|
1544
|
+
async def aio(
|
|
1545
|
+
self,
|
|
1546
|
+
/,
|
|
1547
|
+
path: typing.Union[pathlib.PurePosixPath, str],
|
|
1548
|
+
image: modal.image.Image,
|
|
1549
|
+
*,
|
|
1550
|
+
_experimental_encryption_key: typing.Optional[bytes] = None,
|
|
1551
|
+
) -> None:
|
|
1552
|
+
"""Mount an Image at a specified path in this Sidecar container.
|
|
1553
|
+
|
|
1554
|
+
`path` should be a directory that is **not** the root path (`/`). If the path doesn't exist,
|
|
1555
|
+
it will be created. If it exists and contains data, the previous directory will be replaced
|
|
1556
|
+
by the mount.
|
|
1557
|
+
|
|
1558
|
+
The `image` argument supports any Image that has an object ID, including:
|
|
1559
|
+
- Images built using `image.build()`
|
|
1560
|
+
- Images referenced by ID, e.g. `Image.from_id(...)`
|
|
1561
|
+
- Filesystem/directory snapshots, e.g. created by `.snapshot_directory()` or `.snapshot_filesystem()`
|
|
1562
|
+
- Empty images created with `Image.from_scratch()`
|
|
1563
|
+
|
|
1564
|
+
Args:
|
|
1565
|
+
path: Absolute mount point directory inside the Sidecar container (not `/`).
|
|
1566
|
+
image: Image to mount at `path` (must be built, referenced by ID, or snapshot-based as described above).
|
|
1567
|
+
|
|
1568
|
+
Examples:
|
|
1569
|
+
```py notest
|
|
1570
|
+
sidecar_1.mount_image("/workspace", modal.Image.from_scratch())
|
|
1571
|
+
workspace_snapshot = sidecar_1.snapshot_directory("/workspace")
|
|
1572
|
+
|
|
1573
|
+
# You can later mount this snapshot in another Sidecar:
|
|
1574
|
+
sidecar_2.mount_image("/workspace", workspace_snapshot)
|
|
1575
|
+
sidecar_2.filesystem.list_files("/workspace")
|
|
1576
|
+
```
|
|
1577
|
+
"""
|
|
1578
|
+
...
|
|
1579
|
+
|
|
1580
|
+
mount_image: __mount_image_spec
|
|
1581
|
+
|
|
1582
|
+
class __unmount_image_spec(typing_extensions.Protocol):
|
|
1583
|
+
def __call__(self, /, path: typing.Union[pathlib.PurePosixPath, str]) -> None:
|
|
1584
|
+
"""Unmount a previously mounted Image from this Sidecar container.
|
|
1585
|
+
|
|
1586
|
+
`path` must be the exact mount point that was passed to `.mount_image()`.
|
|
1587
|
+
After unmounting, the underlying Sidecar filesystem at that path becomes
|
|
1588
|
+
visible again.
|
|
1589
|
+
|
|
1590
|
+
Args:
|
|
1591
|
+
path: Absolute mount point directory to unmount.
|
|
1592
|
+
"""
|
|
1593
|
+
...
|
|
1594
|
+
|
|
1595
|
+
async def aio(self, /, path: typing.Union[pathlib.PurePosixPath, str]) -> None:
|
|
1596
|
+
"""Unmount a previously mounted Image from this Sidecar container.
|
|
1597
|
+
|
|
1598
|
+
`path` must be the exact mount point that was passed to `.mount_image()`.
|
|
1599
|
+
After unmounting, the underlying Sidecar filesystem at that path becomes
|
|
1600
|
+
visible again.
|
|
1601
|
+
|
|
1602
|
+
Args:
|
|
1603
|
+
path: Absolute mount point directory to unmount.
|
|
1604
|
+
"""
|
|
1605
|
+
...
|
|
1606
|
+
|
|
1607
|
+
unmount_image: __unmount_image_spec
|
|
1608
|
+
|
|
1609
|
+
class __snapshot_directory_spec(typing_extensions.Protocol):
|
|
1610
|
+
def __call__(
|
|
1611
|
+
self,
|
|
1612
|
+
/,
|
|
1613
|
+
path: typing.Union[pathlib.PurePosixPath, str],
|
|
1614
|
+
*,
|
|
1615
|
+
timeout: int = 55,
|
|
1616
|
+
ttl: typing.Optional[int] = 2592000,
|
|
1617
|
+
_experimental_encryption_key: typing.Optional[bytes] = None,
|
|
1618
|
+
) -> modal.image.Image:
|
|
1619
|
+
"""Snapshot a directory in this Sidecar container, creating a new Image with its content.
|
|
1620
|
+
|
|
1621
|
+
`timeout` If the snapshot does not return within that window, the call is cancelled
|
|
1622
|
+
and `modal.exception.TimeoutError` is raised.
|
|
1623
|
+
|
|
1624
|
+
`ttl` The resulting Image is retained for `ttl` seconds (default: 30 days).
|
|
1625
|
+
Pass `ttl=None` to retain the Image indefinitely.
|
|
1626
|
+
|
|
1627
|
+
The returned Image can be used anywhere an Image is accepted, including
|
|
1628
|
+
as a mount or as the base filesystem for another container.
|
|
1629
|
+
|
|
1630
|
+
Args:
|
|
1631
|
+
path: Absolute path of the directory inside the Sidecar container to snapshot.
|
|
1632
|
+
|
|
1633
|
+
Returns:
|
|
1634
|
+
An `Image` containing the directory contents.
|
|
1635
|
+
|
|
1636
|
+
Examples:
|
|
1637
|
+
```py notest
|
|
1638
|
+
workspace_snapshot = sidecar_1.snapshot_directory("/workspace")
|
|
1639
|
+
|
|
1640
|
+
# You can later mount this snapshot in another Sidecar:
|
|
1641
|
+
sidecar_2.mount_image("/workspace", workspace_snapshot)
|
|
1642
|
+
sidecar_2.filesystem.list_files("/workspace")
|
|
1643
|
+
```
|
|
1644
|
+
"""
|
|
1645
|
+
...
|
|
1646
|
+
|
|
1647
|
+
async def aio(
|
|
1648
|
+
self,
|
|
1649
|
+
/,
|
|
1650
|
+
path: typing.Union[pathlib.PurePosixPath, str],
|
|
1651
|
+
*,
|
|
1652
|
+
timeout: int = 55,
|
|
1653
|
+
ttl: typing.Optional[int] = 2592000,
|
|
1654
|
+
_experimental_encryption_key: typing.Optional[bytes] = None,
|
|
1655
|
+
) -> modal.image.Image:
|
|
1656
|
+
"""Snapshot a directory in this Sidecar container, creating a new Image with its content.
|
|
1657
|
+
|
|
1658
|
+
`timeout` If the snapshot does not return within that window, the call is cancelled
|
|
1659
|
+
and `modal.exception.TimeoutError` is raised.
|
|
1660
|
+
|
|
1661
|
+
`ttl` The resulting Image is retained for `ttl` seconds (default: 30 days).
|
|
1662
|
+
Pass `ttl=None` to retain the Image indefinitely.
|
|
1663
|
+
|
|
1664
|
+
The returned Image can be used anywhere an Image is accepted, including
|
|
1665
|
+
as a mount or as the base filesystem for another container.
|
|
1666
|
+
|
|
1667
|
+
Args:
|
|
1668
|
+
path: Absolute path of the directory inside the Sidecar container to snapshot.
|
|
1669
|
+
|
|
1670
|
+
Returns:
|
|
1671
|
+
An `Image` containing the directory contents.
|
|
1672
|
+
|
|
1673
|
+
Examples:
|
|
1674
|
+
```py notest
|
|
1675
|
+
workspace_snapshot = sidecar_1.snapshot_directory("/workspace")
|
|
1676
|
+
|
|
1677
|
+
# You can later mount this snapshot in another Sidecar:
|
|
1678
|
+
sidecar_2.mount_image("/workspace", workspace_snapshot)
|
|
1679
|
+
sidecar_2.filesystem.list_files("/workspace")
|
|
1680
|
+
```
|
|
1681
|
+
"""
|
|
1682
|
+
...
|
|
1683
|
+
|
|
1684
|
+
snapshot_directory: __snapshot_directory_spec
|
|
1685
|
+
|
|
1423
1686
|
class __wait_spec(typing_extensions.Protocol):
|
|
1424
1687
|
def __call__(self, /, raise_on_termination: bool = True) -> None: ...
|
|
1425
1688
|
async def aio(self, /, raise_on_termination: bool = True) -> None: ...
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|