modal 1.4.4.dev6__tar.gz → 1.4.4.dev8__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.4.dev6 → modal-1.4.4.dev8}/PKG-INFO +1 -1
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_runtime/asgi.py +1 -1
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/cli/shell.py +12 -10
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/client.pyi +2 -2
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/io_streams.py +1 -1
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/io_streams.pyi +2 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/sandbox.py +78 -20
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/sandbox.pyi +88 -33
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/sandbox_fs.py +21 -16
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/sandbox_fs.pyi +9 -2
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal.egg-info/PKG-INFO +1 -1
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal_version/__init__.py +1 -1
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/LICENSE +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/README.md +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/__init__.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/__main__.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_billing.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_clustered_functions.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_clustered_functions.pyi +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_container_entrypoint.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_environments.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_function_variants.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_functions.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_grpc_client.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_ipython.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_load_context.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_location.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_logs.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_object.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_output/__init__.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_output/manager.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_output/pty.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_output/rich.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_output/status.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_partial_function.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_resolver.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_resources.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_runtime/__init__.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_runtime/container_io_manager.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_runtime/container_io_manager.pyi +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_runtime/execution_context.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_runtime/execution_context.pyi +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_runtime/gpu_memory_snapshot.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_runtime/telemetry.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_runtime/user_code_event_loop.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_runtime/user_code_imports.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_serialization.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_server.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_traceback.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_tunnel.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_tunnel.pyi +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_type_manager.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_utils/__init__.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_utils/app_utils.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_utils/async_utils.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_utils/auth_token_manager.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_utils/blob_utils.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_utils/browser_utils.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_utils/bytes_io_segment_payload.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_utils/deprecation.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_utils/docker_utils.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_utils/function_utils.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_utils/git_utils.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_utils/grpc_testing.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_utils/grpc_utils.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_utils/hash_utils.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_utils/http_utils.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_utils/jwt_utils.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_utils/logger.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_utils/mount_utils.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_utils/name_utils.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_utils/package_utils.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_utils/pattern_utils.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_utils/rand_pb_testing.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_utils/sandbox_fs_utils.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_utils/shell_utils.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_utils/task_command_router_client.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_utils/time_utils.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_vendor/__init__.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_vendor/a2wsgi_wsgi.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_vendor/cloudpickle.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_vendor/tblib.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_vendor/version.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/_watcher.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/app.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/app.pyi +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/billing.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/builder/2023.12.312.txt +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/builder/2023.12.txt +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/builder/2024.04.txt +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/builder/2024.10.txt +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/builder/2025.06.txt +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/builder/PREVIEW.txt +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/builder/README.md +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/builder/base-images.json +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/call_graph.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/cli/__init__.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/cli/_download.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/cli/_help.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/cli/_traceback.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/cli/app.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/cli/billing.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/cli/bootstrap.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/cli/changelog.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/cli/cluster.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/cli/config.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/cli/container.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/cli/dashboard.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/cli/dict.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/cli/entry_point.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/cli/environment.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/cli/import_refs.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/cli/launch.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/cli/logo.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/cli/network_file_system.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/cli/profile.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/cli/programs/__init__.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/cli/programs/run_jupyter.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/cli/programs/vscode.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/cli/queues.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/cli/run.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/cli/secret.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/cli/selector.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/cli/token.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/cli/utils.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/cli/volume.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/client.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/cloud_bucket_mount.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/cloud_bucket_mount.pyi +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/cls.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/cls.pyi +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/config.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/container_process.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/container_process.pyi +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/dict.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/dict.pyi +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/environments.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/environments.pyi +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/exception.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/experimental/__init__.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/experimental/flash.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/experimental/flash.pyi +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/experimental/ipython.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/file_io.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/file_io.pyi +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/file_pattern_matcher.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/functions.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/functions.pyi +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/image.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/image.pyi +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/mount.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/mount.pyi +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/network_file_system.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/network_file_system.pyi +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/object.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/object.pyi +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/output.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/parallel_map.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/parallel_map.pyi +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/partial_function.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/partial_function.pyi +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/proxy.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/proxy.pyi +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/py.typed +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/queue.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/queue.pyi +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/retries.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/runner.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/runner.pyi +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/running_app.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/schedule.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/scheduler_placement.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/secret.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/secret.pyi +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/server.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/server.pyi +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/serving.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/serving.pyi +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/snapshot.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/snapshot.pyi +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/stream_type.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/token_flow.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/token_flow.pyi +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/volume.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal/volume.pyi +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal.egg-info/SOURCES.txt +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal.egg-info/dependency_links.txt +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal.egg-info/entry_points.txt +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal.egg-info/requires.txt +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal.egg-info/top_level.txt +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal_docs/__init__.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal_docs/gen_cli_docs.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal_docs/gen_cli_docs_main.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal_docs/gen_reference_docs.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal_docs/gen_reference_docs_main.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal_docs/mdmd/__init__.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal_docs/mdmd/mdmd.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal_docs/mdmd/signatures.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal_proto/__init__.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal_proto/api_grpc.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal_proto/api_pb2.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal_proto/api_pb2.pyi +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal_proto/api_pb2_grpc.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal_proto/api_pb2_grpc.pyi +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal_proto/modal_api_grpc.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal_proto/py.typed +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal_proto/task_command_router_grpc.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal_proto/task_command_router_pb2.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal_proto/task_command_router_pb2.pyi +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal_proto/task_command_router_pb2_grpc.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal_proto/task_command_router_pb2_grpc.pyi +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/modal_version/__main__.py +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/pyproject.toml +0 -0
- {modal-1.4.4.dev6 → modal-1.4.4.dev8}/setup.cfg +0 -0
|
@@ -285,7 +285,7 @@ def wait_for_web_server(host: str, port: int, *, timeout: float) -> None:
|
|
|
285
285
|
start_time = time.monotonic()
|
|
286
286
|
while True:
|
|
287
287
|
try:
|
|
288
|
-
with socket.create_connection((host, port), timeout=timeout):
|
|
288
|
+
with socket.create_connection((host, port), timeout=min(timeout, 1.0)):
|
|
289
289
|
break
|
|
290
290
|
except OSError as ex:
|
|
291
291
|
time.sleep(0.01)
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import platform
|
|
3
3
|
import shlex
|
|
4
4
|
from pathlib import Path, PurePosixPath
|
|
5
|
-
from typing import Any, Callable, Iterable, Optional
|
|
5
|
+
from typing import Any, Callable, Iterable, Optional, Union
|
|
6
6
|
|
|
7
7
|
import click
|
|
8
8
|
from click import ClickException
|
|
@@ -10,12 +10,13 @@ from click import ClickException
|
|
|
10
10
|
from .._environments import ensure_env
|
|
11
11
|
from .._functions import _FunctionSpec
|
|
12
12
|
from ..app import App
|
|
13
|
+
from ..container_process import ContainerProcess
|
|
13
14
|
from ..exception import InvalidError, NotFoundError
|
|
14
15
|
from ..functions import Function
|
|
15
16
|
from ..image import Image
|
|
16
17
|
from ..mount import _Mount
|
|
17
18
|
from ..runner import interactive_shell
|
|
18
|
-
from ..sandbox import Sandbox
|
|
19
|
+
from ..sandbox import _MAIN_CONTAINER_NAME, Sandbox
|
|
19
20
|
from ..secret import Secret
|
|
20
21
|
from ..stream_type import StreamType
|
|
21
22
|
from ..volume import Volume
|
|
@@ -105,8 +106,8 @@ def _is_running_container_ref(ref: Optional[str]) -> bool:
|
|
|
105
106
|
return _is_valid_modal_id(sandbox_id, "sb-") or _is_valid_modal_id(ref, "ta-")
|
|
106
107
|
|
|
107
108
|
|
|
108
|
-
def
|
|
109
|
-
"""Shell into a
|
|
109
|
+
def _start_shell_in_sidecar_container(sandbox_id: str, container_name: str, cmd: str, pty: bool) -> None:
|
|
110
|
+
"""Shell into a sidecar container within a sandbox."""
|
|
110
111
|
try:
|
|
111
112
|
sandbox = Sandbox.from_id(sandbox_id)
|
|
112
113
|
except NotFoundError:
|
|
@@ -115,18 +116,19 @@ def _start_shell_in_sandbox_container(sandbox_id: str, container_name: str, cmd:
|
|
|
115
116
|
raise ClickException(f"Error connecting to Sandbox '{sandbox_id}': {str(e)}")
|
|
116
117
|
|
|
117
118
|
try:
|
|
118
|
-
sandbox_container = sandbox.
|
|
119
|
+
sandbox_container = sandbox._experimental_sidecars.get(name=container_name)
|
|
120
|
+
process: Union[ContainerProcess[bytes], ContainerProcess[str]]
|
|
119
121
|
if pty:
|
|
120
122
|
# PTY output is raw terminal bytes, not text; strict UTF-8 decode
|
|
121
123
|
# crashes on the first non-UTF-8 byte (e.g. vim drawing a Latin-1
|
|
122
124
|
# file under LC_CTYPE=C). See the matching call in `_exec_impl`.
|
|
123
|
-
process = sandbox_container.exec(*shlex.split(cmd), pty=
|
|
125
|
+
process = sandbox_container.exec(*shlex.split(cmd), pty=True, text=False)
|
|
124
126
|
process.attach()
|
|
125
127
|
else:
|
|
126
128
|
process = sandbox_container.exec(
|
|
127
|
-
*shlex.split(cmd), pty=
|
|
129
|
+
*shlex.split(cmd), pty=False, text=False, stdout=StreamType.STDOUT, stderr=StreamType.STDOUT
|
|
128
130
|
)
|
|
129
|
-
process.wait()
|
|
131
|
+
_ = process.wait()
|
|
130
132
|
except NotFoundError:
|
|
131
133
|
raise ClickException(f"Container '{container_name}' not found in Sandbox '{sandbox_id}'.")
|
|
132
134
|
except Exception as e:
|
|
@@ -136,8 +138,8 @@ def _start_shell_in_sandbox_container(sandbox_id: str, container_name: str, cmd:
|
|
|
136
138
|
def _start_shell_in_running_container(ref: str, cmd: str, pty: bool) -> None:
|
|
137
139
|
sandbox_id, container_name = _parse_sandbox_container_ref(ref)
|
|
138
140
|
|
|
139
|
-
if container_name is not None:
|
|
140
|
-
return
|
|
141
|
+
if container_name is not None and container_name != _MAIN_CONTAINER_NAME:
|
|
142
|
+
return _start_shell_in_sidecar_container(sandbox_id, container_name, cmd, pty)
|
|
141
143
|
|
|
142
144
|
if _is_valid_modal_id(sandbox_id, "sb-"):
|
|
143
145
|
try:
|
|
@@ -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.4.
|
|
38
|
+
version: str = "1.4.4.dev8",
|
|
39
39
|
):
|
|
40
40
|
"""mdmd:hidden
|
|
41
41
|
The Modal client object is not intended to be instantiated directly by users.
|
|
@@ -175,7 +175,7 @@ class Client:
|
|
|
175
175
|
server_url: str,
|
|
176
176
|
client_type: int,
|
|
177
177
|
credentials: typing.Optional[tuple[str, str]],
|
|
178
|
-
version: str = "1.4.4.
|
|
178
|
+
version: str = "1.4.4.dev8",
|
|
179
179
|
):
|
|
180
180
|
"""mdmd:hidden
|
|
181
181
|
The Modal client object is not intended to be instantiated directly by users.
|
|
@@ -501,7 +501,7 @@ class _StreamReader(Generic[T]):
|
|
|
501
501
|
MAX_BUFFER_SIZE = 2 * 1024 * 1024
|
|
502
502
|
# Larger buffer limit for the exec path via the task command router.
|
|
503
503
|
# This applies only to task_exec_stdin_write; sandbox stdin via the server keeps MAX_BUFFER_SIZE.
|
|
504
|
-
TASK_COMMAND_ROUTER_MAX_BUFFER_SIZE = 16 * 1024 * 1024
|
|
504
|
+
TASK_COMMAND_ROUTER_MAX_BUFFER_SIZE: int = 16 * 1024 * 1024
|
|
505
505
|
|
|
506
506
|
|
|
507
507
|
@dataclass(frozen=True)
|
|
@@ -5,6 +5,7 @@ import enum
|
|
|
5
5
|
import json
|
|
6
6
|
import os
|
|
7
7
|
import time
|
|
8
|
+
import typing
|
|
8
9
|
import uuid
|
|
9
10
|
from collections.abc import AsyncGenerator, Collection, Sequence
|
|
10
11
|
from dataclasses import dataclass
|
|
@@ -1385,10 +1386,10 @@ class _Sandbox(_Object, type_prefix="sb"):
|
|
|
1385
1386
|
return self._command_router_client
|
|
1386
1387
|
|
|
1387
1388
|
@property
|
|
1388
|
-
def
|
|
1389
|
-
"""Manage
|
|
1389
|
+
def _experimental_sidecars(self) -> "_SidecarManager":
|
|
1390
|
+
"""Manage sidecar containers running in this Sandbox."""
|
|
1390
1391
|
self._ensure_attached()
|
|
1391
|
-
return
|
|
1392
|
+
return _SidecarManager(self)
|
|
1392
1393
|
|
|
1393
1394
|
@overload
|
|
1394
1395
|
async def exec(
|
|
@@ -1853,10 +1854,11 @@ class _Sandbox(_Object, type_prefix="sb"):
|
|
|
1853
1854
|
before_timestamp = resp.sandboxes[-1].created_at
|
|
1854
1855
|
|
|
1855
1856
|
|
|
1856
|
-
class
|
|
1857
|
+
class _SidecarContainer:
|
|
1857
1858
|
"""Handle to an additional container running in a Sandbox."""
|
|
1858
1859
|
|
|
1859
1860
|
_result: Optional[api_pb2.GenericResult]
|
|
1861
|
+
_filesystem: Optional[_SandboxFilesystem]
|
|
1860
1862
|
|
|
1861
1863
|
def __init__(
|
|
1862
1864
|
self,
|
|
@@ -1869,6 +1871,7 @@ class _SandboxContainer:
|
|
|
1869
1871
|
self._container_id = container_id
|
|
1870
1872
|
self._container_name = container_name
|
|
1871
1873
|
self._result = result
|
|
1874
|
+
self._filesystem = None
|
|
1872
1875
|
|
|
1873
1876
|
@property
|
|
1874
1877
|
def object_id(self) -> str:
|
|
@@ -1879,9 +1882,9 @@ class _SandboxContainer:
|
|
|
1879
1882
|
return self._container_name
|
|
1880
1883
|
|
|
1881
1884
|
@staticmethod
|
|
1882
|
-
def _from_container_info(sandbox: "_Sandbox", container_info: sr_pb2.TaskContainerInfo) -> "
|
|
1885
|
+
def _from_container_info(sandbox: "_Sandbox", container_info: sr_pb2.TaskContainerInfo) -> "_SidecarContainer":
|
|
1883
1886
|
result = container_info.result if container_info.HasField("result") else None
|
|
1884
|
-
return
|
|
1887
|
+
return _SidecarContainer(sandbox, container_info.container_id, container_info.container_name, result)
|
|
1885
1888
|
|
|
1886
1889
|
async def _get_command_router(self) -> tuple[str, "TaskCommandRouterClient"]:
|
|
1887
1890
|
"""Get task ID and command router client."""
|
|
@@ -1889,6 +1892,40 @@ class _SandboxContainer:
|
|
|
1889
1892
|
command_router_client = await self._sandbox._get_command_router_client(task_id)
|
|
1890
1893
|
return task_id, command_router_client
|
|
1891
1894
|
|
|
1895
|
+
@typing.overload
|
|
1896
|
+
async def exec(
|
|
1897
|
+
self,
|
|
1898
|
+
*args: str,
|
|
1899
|
+
stdout: StreamType = StreamType.PIPE,
|
|
1900
|
+
stderr: StreamType = StreamType.PIPE,
|
|
1901
|
+
timeout: Optional[int] = None,
|
|
1902
|
+
workdir: Optional[str] = None,
|
|
1903
|
+
env: Optional[dict[str, Optional[str]]] = None,
|
|
1904
|
+
secrets: Optional[Collection[_Secret]] = None,
|
|
1905
|
+
text: Literal[True] = True,
|
|
1906
|
+
bufsize: Literal[-1, 1] = -1,
|
|
1907
|
+
# Enable a PTY for the command. When enabled, all output (stdout and stderr from the
|
|
1908
|
+
# process) is multiplexed into stdout, and the stderr stream is effectively empty.
|
|
1909
|
+
pty: bool = False,
|
|
1910
|
+
) -> _ContainerProcess[str]: ...
|
|
1911
|
+
|
|
1912
|
+
@typing.overload
|
|
1913
|
+
async def exec(
|
|
1914
|
+
self,
|
|
1915
|
+
*args: str,
|
|
1916
|
+
stdout: StreamType = StreamType.PIPE,
|
|
1917
|
+
stderr: StreamType = StreamType.PIPE,
|
|
1918
|
+
timeout: Optional[int] = None,
|
|
1919
|
+
workdir: Optional[str] = None,
|
|
1920
|
+
env: Optional[dict[str, Optional[str]]] = None,
|
|
1921
|
+
secrets: Optional[Collection[_Secret]] = None,
|
|
1922
|
+
text: Literal[False],
|
|
1923
|
+
bufsize: Literal[-1, 1] = -1,
|
|
1924
|
+
# Enable a PTY for the command. When enabled, all output (stdout and stderr from the
|
|
1925
|
+
# process) is multiplexed into stdout, and the stderr stream is effectively empty.
|
|
1926
|
+
pty: bool = False,
|
|
1927
|
+
) -> _ContainerProcess[bytes]: ...
|
|
1928
|
+
|
|
1892
1929
|
async def exec(
|
|
1893
1930
|
self,
|
|
1894
1931
|
*args: str,
|
|
@@ -1919,6 +1956,13 @@ class _SandboxContainer:
|
|
|
1919
1956
|
container_id=self._container_id,
|
|
1920
1957
|
)
|
|
1921
1958
|
|
|
1959
|
+
@property
|
|
1960
|
+
def filesystem(self) -> _SandboxFilesystem:
|
|
1961
|
+
"""Namespace for filesystem APIs."""
|
|
1962
|
+
if self._filesystem is None:
|
|
1963
|
+
self._filesystem = _SandboxFilesystem(self)
|
|
1964
|
+
return self._filesystem
|
|
1965
|
+
|
|
1922
1966
|
async def wait(self, raise_on_termination: bool = True) -> None:
|
|
1923
1967
|
if self._result is not None and self._result.status != api_pb2.GenericResult.GENERIC_STATUS_UNSPECIFIED:
|
|
1924
1968
|
if self._result.status == api_pb2.GenericResult.GENERIC_STATUS_TERMINATED and raise_on_termination:
|
|
@@ -1987,8 +2031,11 @@ class _SandboxContainer:
|
|
|
1987
2031
|
return _result_returncode(self._result)
|
|
1988
2032
|
|
|
1989
2033
|
|
|
1990
|
-
|
|
1991
|
-
|
|
2034
|
+
_MAIN_CONTAINER_NAME: str = "main"
|
|
2035
|
+
|
|
2036
|
+
|
|
2037
|
+
class _SidecarManager:
|
|
2038
|
+
"""Creates and manages sidecar containers in a Sandbox."""
|
|
1992
2039
|
|
|
1993
2040
|
def __init__(self, sandbox: _Sandbox) -> None:
|
|
1994
2041
|
self._sandbox = sandbox
|
|
@@ -2007,22 +2054,24 @@ class _SandboxContainerManager:
|
|
|
2007
2054
|
env: Optional[dict[str, str]] = None,
|
|
2008
2055
|
secrets: Optional[Collection[_Secret]] = None,
|
|
2009
2056
|
workdir: Optional[str] = None,
|
|
2010
|
-
) ->
|
|
2057
|
+
) -> _SidecarContainer:
|
|
2058
|
+
if name == _MAIN_CONTAINER_NAME:
|
|
2059
|
+
raise InvalidError(f"The name {_MAIN_CONTAINER_NAME!r} is reserved for the sandbox's main container.")
|
|
2011
2060
|
if workdir is not None and not workdir.startswith("/"):
|
|
2012
2061
|
raise InvalidError(f"workdir must be an absolute path, got: {workdir}")
|
|
2013
2062
|
_validate_exec_args(args)
|
|
2014
2063
|
|
|
2015
2064
|
if image._mount_layers:
|
|
2016
2065
|
raise InvalidError(
|
|
2017
|
-
"Sandbox.
|
|
2066
|
+
"Sandbox._experimental_sidecars.create(image=...) only supports pre-built images. "
|
|
2018
2067
|
"When using `add_local*` methods, specify `copy=True` and call `.build()` before passing "
|
|
2019
|
-
"the image to `.
|
|
2068
|
+
"the image to `._experimental_sidecars.create()`:\n\nE.g.\n"
|
|
2020
2069
|
'img = modal.Image.debian_slim().add_local_file("foo", "/foo", copy=True).build(app)\n'
|
|
2021
|
-
'sandbox.
|
|
2070
|
+
'sandbox._experimental_sidecars.create(name="worker", image=img)'
|
|
2022
2071
|
)
|
|
2023
2072
|
if not image._object_id:
|
|
2024
2073
|
raise InvalidError(
|
|
2025
|
-
"Sandbox.
|
|
2074
|
+
"Sandbox._experimental_sidecars.create(image=...) currently only supports Images that are "
|
|
2026
2075
|
"either:\n"
|
|
2027
2076
|
"- prebuilt using `image.build()`\n"
|
|
2028
2077
|
"- referenced by id, e.g. `Image.from_id()`\n"
|
|
@@ -2048,9 +2097,14 @@ class _SandboxContainerManager:
|
|
|
2048
2097
|
create_resp = await command_router_client.container_create(create_req)
|
|
2049
2098
|
container_id = create_resp.container_id
|
|
2050
2099
|
container_name = create_resp.container_name or name
|
|
2051
|
-
return
|
|
2100
|
+
return _SidecarContainer(self._sandbox, container_id, container_name)
|
|
2052
2101
|
|
|
2053
|
-
async def get(self, *, name: str, include_terminated: bool = False) -> "
|
|
2102
|
+
async def get(self, *, name: str, include_terminated: bool = False) -> "_SidecarContainer":
|
|
2103
|
+
if name == _MAIN_CONTAINER_NAME:
|
|
2104
|
+
raise InvalidError(
|
|
2105
|
+
"Cannot get the main sandbox container through the sidecars API. "
|
|
2106
|
+
"Use Sandbox methods directly to interact with the main container."
|
|
2107
|
+
)
|
|
2054
2108
|
task_id, command_router_client = await self._get_command_router()
|
|
2055
2109
|
resp = await command_router_client.container_get(
|
|
2056
2110
|
sr_pb2.TaskContainerGetRequest(
|
|
@@ -2059,16 +2113,20 @@ class _SandboxContainerManager:
|
|
|
2059
2113
|
include_terminated=include_terminated,
|
|
2060
2114
|
)
|
|
2061
2115
|
)
|
|
2062
|
-
return
|
|
2116
|
+
return _SidecarContainer._from_container_info(self._sandbox, resp.container)
|
|
2063
2117
|
|
|
2064
|
-
async def list(self, include_terminated: bool = False) -> builtins.list[
|
|
2118
|
+
async def list(self, include_terminated: bool = False) -> builtins.list[_SidecarContainer]:
|
|
2065
2119
|
task_id, command_router_client = await self._get_command_router()
|
|
2066
2120
|
resp = await command_router_client.container_list(
|
|
2067
2121
|
sr_pb2.TaskContainerListRequest(task_id=task_id, include_terminated=include_terminated)
|
|
2068
2122
|
)
|
|
2069
|
-
return [
|
|
2123
|
+
return [
|
|
2124
|
+
_SidecarContainer._from_container_info(self._sandbox, container)
|
|
2125
|
+
for container in resp.containers
|
|
2126
|
+
if container.container_name != _MAIN_CONTAINER_NAME
|
|
2127
|
+
]
|
|
2070
2128
|
|
|
2071
2129
|
|
|
2072
|
-
|
|
2073
|
-
|
|
2130
|
+
SidecarContainer = synchronize_api(_SidecarContainer)
|
|
2131
|
+
SidecarManager = synchronize_api(_SidecarManager)
|
|
2074
2132
|
Sandbox = synchronize_api(_Sandbox)
|
|
@@ -533,8 +533,8 @@ class _Sandbox(modal._object._Object):
|
|
|
533
533
|
self, task_id: str
|
|
534
534
|
) -> modal._utils.task_command_router_client.TaskCommandRouterClient: ...
|
|
535
535
|
@property
|
|
536
|
-
def
|
|
537
|
-
"""Manage
|
|
536
|
+
def _experimental_sidecars(self) -> _SidecarManager:
|
|
537
|
+
"""Manage sidecar containers running in this Sandbox."""
|
|
538
538
|
...
|
|
539
539
|
|
|
540
540
|
@typing.overload
|
|
@@ -697,10 +697,11 @@ class _Sandbox(modal._object._Object):
|
|
|
697
697
|
"""
|
|
698
698
|
...
|
|
699
699
|
|
|
700
|
-
class
|
|
700
|
+
class _SidecarContainer:
|
|
701
701
|
"""Handle to an additional container running in a Sandbox."""
|
|
702
702
|
|
|
703
703
|
_result: typing.Optional[modal_proto.api_pb2.GenericResult]
|
|
704
|
+
_filesystem: typing.Optional[modal.sandbox_fs._SandboxFilesystem]
|
|
704
705
|
|
|
705
706
|
def __init__(
|
|
706
707
|
self,
|
|
@@ -719,11 +720,12 @@ class _SandboxContainer:
|
|
|
719
720
|
@staticmethod
|
|
720
721
|
def _from_container_info(
|
|
721
722
|
sandbox: _Sandbox, container_info: modal_proto.task_command_router_pb2.TaskContainerInfo
|
|
722
|
-
) ->
|
|
723
|
+
) -> _SidecarContainer: ...
|
|
723
724
|
async def _get_command_router(self) -> tuple[str, modal._utils.task_command_router_client.TaskCommandRouterClient]:
|
|
724
725
|
"""Get task ID and command router client."""
|
|
725
726
|
...
|
|
726
727
|
|
|
728
|
+
@typing.overload
|
|
727
729
|
async def exec(
|
|
728
730
|
self,
|
|
729
731
|
*args: str,
|
|
@@ -733,12 +735,29 @@ class _SandboxContainer:
|
|
|
733
735
|
workdir: typing.Optional[str] = None,
|
|
734
736
|
env: typing.Optional[dict[str, typing.Optional[str]]] = None,
|
|
735
737
|
secrets: typing.Optional[collections.abc.Collection[modal.secret._Secret]] = None,
|
|
736
|
-
text:
|
|
738
|
+
text: typing.Literal[True] = True,
|
|
739
|
+
bufsize: typing.Literal[-1, 1] = -1,
|
|
740
|
+
pty: bool = False,
|
|
741
|
+
) -> modal.container_process._ContainerProcess[str]: ...
|
|
742
|
+
@typing.overload
|
|
743
|
+
async def exec(
|
|
744
|
+
self,
|
|
745
|
+
*args: str,
|
|
746
|
+
stdout: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
|
|
747
|
+
stderr: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
|
|
748
|
+
timeout: typing.Optional[int] = None,
|
|
749
|
+
workdir: typing.Optional[str] = None,
|
|
750
|
+
env: typing.Optional[dict[str, typing.Optional[str]]] = None,
|
|
751
|
+
secrets: typing.Optional[collections.abc.Collection[modal.secret._Secret]] = None,
|
|
752
|
+
text: typing.Literal[False],
|
|
737
753
|
bufsize: typing.Literal[-1, 1] = -1,
|
|
738
754
|
pty: bool = False,
|
|
739
|
-
) ->
|
|
740
|
-
|
|
741
|
-
|
|
755
|
+
) -> modal.container_process._ContainerProcess[bytes]: ...
|
|
756
|
+
@property
|
|
757
|
+
def filesystem(self) -> modal.sandbox_fs._SandboxFilesystem:
|
|
758
|
+
"""Namespace for filesystem APIs."""
|
|
759
|
+
...
|
|
760
|
+
|
|
742
761
|
async def wait(self, raise_on_termination: bool = True) -> None: ...
|
|
743
762
|
async def poll(self) -> typing.Optional[int]: ...
|
|
744
763
|
@typing.overload
|
|
@@ -746,8 +765,8 @@ class _SandboxContainer:
|
|
|
746
765
|
@typing.overload
|
|
747
766
|
async def terminate(self, *, wait: typing.Literal[False] = False) -> None: ...
|
|
748
767
|
|
|
749
|
-
class
|
|
750
|
-
"""Creates and manages
|
|
768
|
+
class _SidecarManager:
|
|
769
|
+
"""Creates and manages sidecar containers in a Sandbox."""
|
|
751
770
|
def __init__(self, sandbox: _Sandbox) -> None:
|
|
752
771
|
"""Initialize self. See help(type(self)) for accurate signature."""
|
|
753
772
|
...
|
|
@@ -764,14 +783,15 @@ class _SandboxContainerManager:
|
|
|
764
783
|
env: typing.Optional[dict[str, str]] = None,
|
|
765
784
|
secrets: typing.Optional[collections.abc.Collection[modal.secret._Secret]] = None,
|
|
766
785
|
workdir: typing.Optional[str] = None,
|
|
767
|
-
) ->
|
|
768
|
-
async def get(self, *, name: str, include_terminated: bool = False) ->
|
|
769
|
-
async def list(self, include_terminated: bool = False) -> list[
|
|
786
|
+
) -> _SidecarContainer: ...
|
|
787
|
+
async def get(self, *, name: str, include_terminated: bool = False) -> _SidecarContainer: ...
|
|
788
|
+
async def list(self, include_terminated: bool = False) -> list[_SidecarContainer]: ...
|
|
770
789
|
|
|
771
|
-
class
|
|
790
|
+
class SidecarContainer:
|
|
772
791
|
"""Handle to an additional container running in a Sandbox."""
|
|
773
792
|
|
|
774
793
|
_result: typing.Optional[modal_proto.api_pb2.GenericResult]
|
|
794
|
+
_filesystem: typing.Optional[modal.sandbox_fs.SandboxFilesystem]
|
|
775
795
|
|
|
776
796
|
def __init__(
|
|
777
797
|
self,
|
|
@@ -787,7 +807,7 @@ class SandboxContainer:
|
|
|
787
807
|
@staticmethod
|
|
788
808
|
def _from_container_info(
|
|
789
809
|
sandbox: Sandbox, container_info: modal_proto.task_command_router_pb2.TaskContainerInfo
|
|
790
|
-
) ->
|
|
810
|
+
) -> SidecarContainer: ...
|
|
791
811
|
|
|
792
812
|
class ___get_command_router_spec(typing_extensions.Protocol):
|
|
793
813
|
def __call__(self, /) -> tuple[str, modal._utils.task_command_router_client.TaskCommandRouterClient]:
|
|
@@ -801,6 +821,7 @@ class SandboxContainer:
|
|
|
801
821
|
_get_command_router: ___get_command_router_spec
|
|
802
822
|
|
|
803
823
|
class __exec_spec(typing_extensions.Protocol):
|
|
824
|
+
@typing.overload
|
|
804
825
|
def __call__(
|
|
805
826
|
self,
|
|
806
827
|
/,
|
|
@@ -811,12 +832,26 @@ class SandboxContainer:
|
|
|
811
832
|
workdir: typing.Optional[str] = None,
|
|
812
833
|
env: typing.Optional[dict[str, typing.Optional[str]]] = None,
|
|
813
834
|
secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
|
|
814
|
-
text:
|
|
835
|
+
text: typing.Literal[True] = True,
|
|
815
836
|
bufsize: typing.Literal[-1, 1] = -1,
|
|
816
837
|
pty: bool = False,
|
|
817
|
-
) ->
|
|
818
|
-
|
|
819
|
-
|
|
838
|
+
) -> modal.container_process.ContainerProcess[str]: ...
|
|
839
|
+
@typing.overload
|
|
840
|
+
def __call__(
|
|
841
|
+
self,
|
|
842
|
+
/,
|
|
843
|
+
*args: str,
|
|
844
|
+
stdout: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
|
|
845
|
+
stderr: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
|
|
846
|
+
timeout: typing.Optional[int] = None,
|
|
847
|
+
workdir: typing.Optional[str] = None,
|
|
848
|
+
env: typing.Optional[dict[str, typing.Optional[str]]] = None,
|
|
849
|
+
secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
|
|
850
|
+
text: typing.Literal[False],
|
|
851
|
+
bufsize: typing.Literal[-1, 1] = -1,
|
|
852
|
+
pty: bool = False,
|
|
853
|
+
) -> modal.container_process.ContainerProcess[bytes]: ...
|
|
854
|
+
@typing.overload
|
|
820
855
|
async def aio(
|
|
821
856
|
self,
|
|
822
857
|
/,
|
|
@@ -827,15 +862,33 @@ class SandboxContainer:
|
|
|
827
862
|
workdir: typing.Optional[str] = None,
|
|
828
863
|
env: typing.Optional[dict[str, typing.Optional[str]]] = None,
|
|
829
864
|
secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
|
|
830
|
-
text:
|
|
865
|
+
text: typing.Literal[True] = True,
|
|
831
866
|
bufsize: typing.Literal[-1, 1] = -1,
|
|
832
867
|
pty: bool = False,
|
|
833
|
-
) ->
|
|
834
|
-
|
|
835
|
-
|
|
868
|
+
) -> modal.container_process.ContainerProcess[str]: ...
|
|
869
|
+
@typing.overload
|
|
870
|
+
async def aio(
|
|
871
|
+
self,
|
|
872
|
+
/,
|
|
873
|
+
*args: str,
|
|
874
|
+
stdout: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
|
|
875
|
+
stderr: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
|
|
876
|
+
timeout: typing.Optional[int] = None,
|
|
877
|
+
workdir: typing.Optional[str] = None,
|
|
878
|
+
env: typing.Optional[dict[str, typing.Optional[str]]] = None,
|
|
879
|
+
secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
|
|
880
|
+
text: typing.Literal[False],
|
|
881
|
+
bufsize: typing.Literal[-1, 1] = -1,
|
|
882
|
+
pty: bool = False,
|
|
883
|
+
) -> modal.container_process.ContainerProcess[bytes]: ...
|
|
836
884
|
|
|
837
885
|
exec: __exec_spec
|
|
838
886
|
|
|
887
|
+
@property
|
|
888
|
+
def filesystem(self) -> modal.sandbox_fs.SandboxFilesystem:
|
|
889
|
+
"""Namespace for filesystem APIs."""
|
|
890
|
+
...
|
|
891
|
+
|
|
839
892
|
class __wait_spec(typing_extensions.Protocol):
|
|
840
893
|
def __call__(self, /, raise_on_termination: bool = True) -> None: ...
|
|
841
894
|
async def aio(self, /, raise_on_termination: bool = True) -> None: ...
|
|
@@ -860,8 +913,8 @@ class SandboxContainer:
|
|
|
860
913
|
|
|
861
914
|
terminate: __terminate_spec
|
|
862
915
|
|
|
863
|
-
class
|
|
864
|
-
"""Creates and manages
|
|
916
|
+
class SidecarManager:
|
|
917
|
+
"""Creates and manages sidecar containers in a Sandbox."""
|
|
865
918
|
def __init__(self, sandbox: Sandbox) -> None: ...
|
|
866
919
|
|
|
867
920
|
class ___get_command_router_spec(typing_extensions.Protocol):
|
|
@@ -885,7 +938,7 @@ class SandboxContainerManager:
|
|
|
885
938
|
env: typing.Optional[dict[str, str]] = None,
|
|
886
939
|
secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
|
|
887
940
|
workdir: typing.Optional[str] = None,
|
|
888
|
-
) ->
|
|
941
|
+
) -> SidecarContainer: ...
|
|
889
942
|
async def aio(
|
|
890
943
|
self,
|
|
891
944
|
/,
|
|
@@ -895,19 +948,19 @@ class SandboxContainerManager:
|
|
|
895
948
|
env: typing.Optional[dict[str, str]] = None,
|
|
896
949
|
secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
|
|
897
950
|
workdir: typing.Optional[str] = None,
|
|
898
|
-
) ->
|
|
951
|
+
) -> SidecarContainer: ...
|
|
899
952
|
|
|
900
953
|
create: __create_spec
|
|
901
954
|
|
|
902
955
|
class __get_spec(typing_extensions.Protocol):
|
|
903
|
-
def __call__(self, /, *, name: str, include_terminated: bool = False) ->
|
|
904
|
-
async def aio(self, /, *, name: str, include_terminated: bool = False) ->
|
|
956
|
+
def __call__(self, /, *, name: str, include_terminated: bool = False) -> SidecarContainer: ...
|
|
957
|
+
async def aio(self, /, *, name: str, include_terminated: bool = False) -> SidecarContainer: ...
|
|
905
958
|
|
|
906
959
|
get: __get_spec
|
|
907
960
|
|
|
908
961
|
class __list_spec(typing_extensions.Protocol):
|
|
909
|
-
def __call__(self, /, include_terminated: bool = False) -> list[
|
|
910
|
-
async def aio(self, /, include_terminated: bool = False) -> list[
|
|
962
|
+
def __call__(self, /, include_terminated: bool = False) -> list[SidecarContainer]: ...
|
|
963
|
+
async def aio(self, /, include_terminated: bool = False) -> list[SidecarContainer]: ...
|
|
911
964
|
|
|
912
965
|
list: __list_spec
|
|
913
966
|
|
|
@@ -1707,8 +1760,8 @@ class Sandbox(modal.object.Object):
|
|
|
1707
1760
|
_get_command_router_client: ___get_command_router_client_spec
|
|
1708
1761
|
|
|
1709
1762
|
@property
|
|
1710
|
-
def
|
|
1711
|
-
"""Manage
|
|
1763
|
+
def _experimental_sidecars(self) -> SidecarManager:
|
|
1764
|
+
"""Manage sidecar containers running in this Sandbox."""
|
|
1712
1765
|
...
|
|
1713
1766
|
|
|
1714
1767
|
class __exec_spec(typing_extensions.Protocol):
|
|
@@ -2060,3 +2113,5 @@ class Sandbox(modal.object.Object):
|
|
|
2060
2113
|
list: typing.ClassVar[__list_spec]
|
|
2061
2114
|
|
|
2062
2115
|
_default_image: modal.image._Image
|
|
2116
|
+
|
|
2117
|
+
_MAIN_CONTAINER_NAME: str
|