modal 1.4.3.dev17__tar.gz → 1.4.3.dev19__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.3.dev17 → modal-1.4.3.dev19}/PKG-INFO +1 -1
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_utils/blob_utils.py +10 -3
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_utils/task_command_router_client.py +5 -14
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/app.py +0 -2
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/cli/cluster.py +1 -4
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/cli/container.py +1 -3
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/client.pyi +2 -2
- modal-1.4.3.dev19/modal/container_process.py +224 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/container_process.pyi +11 -120
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/file_io.py +0 -7
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/io_streams.py +69 -199
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/io_streams.pyi +125 -64
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/sandbox.py +41 -91
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/sandbox.pyi +9 -76
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal.egg-info/PKG-INFO +1 -1
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal_proto/api_pb2.pyi +1 -1
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal_version/__init__.py +1 -1
- modal-1.4.3.dev17/modal/container_process.py +0 -470
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/LICENSE +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/README.md +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/__init__.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/__main__.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_billing.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_clustered_functions.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_clustered_functions.pyi +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_container_entrypoint.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_environments.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_functions.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_grpc_client.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_ipython.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_load_context.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_location.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_logs.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_object.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_output/__init__.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_output/manager.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_output/pty.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_output/rich.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_output/status.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_partial_function.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_resolver.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_resources.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_runtime/__init__.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_runtime/asgi.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_runtime/container_io_manager.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_runtime/container_io_manager.pyi +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_runtime/execution_context.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_runtime/execution_context.pyi +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_runtime/gpu_memory_snapshot.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_runtime/telemetry.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_runtime/user_code_event_loop.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_runtime/user_code_imports.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_serialization.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_server.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_traceback.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_tunnel.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_tunnel.pyi +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_type_manager.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_utils/__init__.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_utils/app_utils.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_utils/async_utils.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_utils/auth_token_manager.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_utils/browser_utils.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_utils/bytes_io_segment_payload.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_utils/deprecation.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_utils/docker_utils.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_utils/function_utils.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_utils/git_utils.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_utils/grpc_testing.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_utils/grpc_utils.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_utils/hash_utils.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_utils/http_utils.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_utils/jwt_utils.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_utils/logger.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_utils/mount_utils.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_utils/name_utils.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_utils/package_utils.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_utils/pattern_utils.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_utils/rand_pb_testing.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_utils/sandbox_fs_utils.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_utils/shell_utils.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_utils/time_utils.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_vendor/__init__.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_vendor/a2wsgi_wsgi.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_vendor/cloudpickle.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_vendor/tblib.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_vendor/version.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/_watcher.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/app.pyi +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/billing.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/builder/2023.12.312.txt +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/builder/2023.12.txt +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/builder/2024.04.txt +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/builder/2024.10.txt +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/builder/2025.06.txt +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/builder/PREVIEW.txt +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/builder/README.md +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/builder/base-images.json +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/call_graph.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/cli/__init__.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/cli/_download.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/cli/_help.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/cli/_traceback.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/cli/app.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/cli/billing.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/cli/bootstrap.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/cli/changelog.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/cli/config.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/cli/dashboard.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/cli/dict.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/cli/entry_point.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/cli/environment.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/cli/import_refs.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/cli/launch.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/cli/logo.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/cli/network_file_system.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/cli/profile.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/cli/programs/__init__.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/cli/programs/run_jupyter.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/cli/programs/vscode.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/cli/queues.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/cli/run.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/cli/secret.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/cli/selector.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/cli/shell.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/cli/token.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/cli/utils.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/cli/volume.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/client.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/cloud_bucket_mount.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/cloud_bucket_mount.pyi +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/cls.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/cls.pyi +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/config.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/dict.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/dict.pyi +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/environments.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/environments.pyi +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/exception.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/experimental/__init__.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/experimental/flash.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/experimental/flash.pyi +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/experimental/ipython.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/file_io.pyi +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/file_pattern_matcher.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/functions.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/functions.pyi +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/image.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/image.pyi +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/mount.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/mount.pyi +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/network_file_system.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/network_file_system.pyi +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/object.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/object.pyi +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/output.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/parallel_map.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/parallel_map.pyi +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/partial_function.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/partial_function.pyi +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/proxy.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/proxy.pyi +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/py.typed +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/queue.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/queue.pyi +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/retries.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/runner.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/runner.pyi +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/running_app.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/sandbox_fs.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/sandbox_fs.pyi +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/schedule.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/scheduler_placement.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/secret.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/secret.pyi +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/server.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/server.pyi +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/serving.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/serving.pyi +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/snapshot.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/snapshot.pyi +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/stream_type.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/token_flow.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/token_flow.pyi +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/volume.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal/volume.pyi +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal.egg-info/SOURCES.txt +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal.egg-info/dependency_links.txt +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal.egg-info/entry_points.txt +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal.egg-info/requires.txt +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal.egg-info/top_level.txt +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal_docs/__init__.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal_docs/gen_cli_docs.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal_docs/gen_cli_docs_main.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal_docs/gen_reference_docs.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal_docs/gen_reference_docs_main.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal_docs/mdmd/__init__.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal_docs/mdmd/mdmd.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal_docs/mdmd/signatures.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal_proto/__init__.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal_proto/api_grpc.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal_proto/api_pb2.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal_proto/api_pb2_grpc.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal_proto/api_pb2_grpc.pyi +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal_proto/modal_api_grpc.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal_proto/py.typed +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal_proto/task_command_router_grpc.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal_proto/task_command_router_pb2.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal_proto/task_command_router_pb2.pyi +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal_proto/task_command_router_pb2_grpc.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal_proto/task_command_router_pb2_grpc.pyi +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/modal_version/__main__.py +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/pyproject.toml +0 -0
- {modal-1.4.3.dev17 → modal-1.4.3.dev19}/setup.cfg +0 -0
|
@@ -717,7 +717,14 @@ def use_md5(url: str) -> bool:
|
|
|
717
717
|
host = urlparse(url).netloc.split(":")[0]
|
|
718
718
|
if host.endswith(".amazonaws.com") or host.endswith(".r2.cloudflarestorage.com"):
|
|
719
719
|
return True
|
|
720
|
-
|
|
720
|
+
if host == "localhost":
|
|
721
721
|
return False
|
|
722
|
-
|
|
723
|
-
|
|
722
|
+
try:
|
|
723
|
+
import ipaddress
|
|
724
|
+
|
|
725
|
+
addr = ipaddress.ip_address(host)
|
|
726
|
+
if addr.is_private or addr.is_loopback:
|
|
727
|
+
return False
|
|
728
|
+
except ValueError:
|
|
729
|
+
pass
|
|
730
|
+
raise Exception(f"Unknown S3 host: {host}")
|
|
@@ -16,7 +16,7 @@ from grpclib import GRPCError, Status
|
|
|
16
16
|
from grpclib.exceptions import StreamTerminatedError
|
|
17
17
|
|
|
18
18
|
from modal.config import logger
|
|
19
|
-
from modal.exception import
|
|
19
|
+
from modal.exception import ExecTimeoutError
|
|
20
20
|
from modal_proto import api_pb2, task_command_router_pb2 as sr_pb2
|
|
21
21
|
from modal_proto.task_command_router_grpc import TaskCommandRouterStub
|
|
22
22
|
|
|
@@ -196,21 +196,12 @@ class TaskCommandRouterClient:
|
|
|
196
196
|
return cls(server_client, task_id, url, jwt, channel, loop, jwt_refresh_lock, sandbox_id=sandbox_id)
|
|
197
197
|
|
|
198
198
|
@classmethod
|
|
199
|
-
async def
|
|
199
|
+
async def init(
|
|
200
200
|
cls,
|
|
201
201
|
server_client,
|
|
202
202
|
task_id: str,
|
|
203
|
-
) ->
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
Returns None if command router access is not enabled (FAILED_PRECONDITION).
|
|
207
|
-
"""
|
|
208
|
-
try:
|
|
209
|
-
resp = await fetch_command_router_access(server_client, task_id)
|
|
210
|
-
except ConflictError:
|
|
211
|
-
logger.debug(f"Command router access is not enabled for task {task_id}")
|
|
212
|
-
return None
|
|
213
|
-
|
|
203
|
+
) -> "TaskCommandRouterClient":
|
|
204
|
+
resp = await fetch_command_router_access(server_client, task_id)
|
|
214
205
|
logger.debug(f"Using command router access for task {task_id}")
|
|
215
206
|
return await cls._connect(server_client, task_id, resp.url, resp.jwt)
|
|
216
207
|
|
|
@@ -241,7 +232,7 @@ class TaskCommandRouterClient:
|
|
|
241
232
|
stream_stdio_retry_delay_factor: float = 2,
|
|
242
233
|
stream_stdio_max_retries: int = 10,
|
|
243
234
|
) -> None:
|
|
244
|
-
"""Callers should not use this directly. Use TaskCommandRouterClient.
|
|
235
|
+
"""Callers should not use this directly. Use TaskCommandRouterClient.init() instead."""
|
|
245
236
|
# Record the loop this instance is bound to so __del__ can safely schedule cleanup
|
|
246
237
|
# even if finalization happens from a different thread (e.g. via synchronicity).
|
|
247
238
|
self._loop = loop
|
|
@@ -778,7 +778,6 @@ class _App:
|
|
|
778
778
|
deprecation_warning(
|
|
779
779
|
(2025, 12, 16),
|
|
780
780
|
"The `max_inputs` parameter is deprecated. Please set `single_use_containers=True` instead.",
|
|
781
|
-
pending=True,
|
|
782
781
|
)
|
|
783
782
|
single_use_containers = max_inputs == 1
|
|
784
783
|
|
|
@@ -987,7 +986,6 @@ class _App:
|
|
|
987
986
|
deprecation_warning(
|
|
988
987
|
(2025, 12, 16),
|
|
989
988
|
"The `max_inputs` parameter is deprecated. Please set `single_use_containers=True` instead.",
|
|
990
|
-
pending=True,
|
|
991
989
|
)
|
|
992
990
|
single_use_containers = max_inputs == 1
|
|
993
991
|
|
|
@@ -16,7 +16,6 @@ from modal.cli.utils import display_table, env_option, is_tty
|
|
|
16
16
|
from modal.client import _Client
|
|
17
17
|
from modal.config import config
|
|
18
18
|
from modal.container_process import _ContainerProcess
|
|
19
|
-
from modal.exception import InvalidError
|
|
20
19
|
from modal.output import OutputManager
|
|
21
20
|
from modal.stream_type import StreamType
|
|
22
21
|
from modal_proto import api_pb2, task_command_router_pb2 as sr_pb2
|
|
@@ -79,9 +78,7 @@ async def shell(cluster_id: str, rank: int = 0):
|
|
|
79
78
|
|
|
80
79
|
pty = is_tty()
|
|
81
80
|
|
|
82
|
-
command_router_client = await TaskCommandRouterClient.
|
|
83
|
-
if command_router_client is None:
|
|
84
|
-
raise InvalidError(f"Command router access is not available for container {task_id}")
|
|
81
|
+
command_router_client = await TaskCommandRouterClient.init(client, task_id)
|
|
85
82
|
|
|
86
83
|
process_id = str(uuid.uuid4())
|
|
87
84
|
|
|
@@ -278,9 +278,7 @@ async def _exec_impl(
|
|
|
278
278
|
|
|
279
279
|
client = await _Client.from_env()
|
|
280
280
|
|
|
281
|
-
command_router_client = await TaskCommandRouterClient.
|
|
282
|
-
if command_router_client is None:
|
|
283
|
-
raise InvalidError(f"Command router access is not available for container {container_id}")
|
|
281
|
+
command_router_client = await TaskCommandRouterClient.init(client, container_id)
|
|
284
282
|
|
|
285
283
|
process_id = str(uuid.uuid4())
|
|
286
284
|
|
|
@@ -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.3.
|
|
38
|
+
version: str = "1.4.3.dev19",
|
|
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.3.
|
|
178
|
+
version: str = "1.4.3.dev19",
|
|
179
179
|
):
|
|
180
180
|
"""mdmd:hidden
|
|
181
181
|
The Modal client object is not intended to be instantiated directly by users.
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
# Copyright Modal Labs 2024
|
|
2
|
+
import asyncio
|
|
3
|
+
import platform
|
|
4
|
+
from typing import Generic, Optional, TypeVar
|
|
5
|
+
|
|
6
|
+
from modal_proto import api_pb2
|
|
7
|
+
|
|
8
|
+
from ._utils.async_utils import TaskContext, synchronize_api
|
|
9
|
+
from ._utils.shell_utils import stream_from_stdin, write_to_fd
|
|
10
|
+
from ._utils.task_command_router_client import TaskCommandRouterClient
|
|
11
|
+
from .client import _Client
|
|
12
|
+
from .config import logger
|
|
13
|
+
from .exception import ExecTimeoutError, InteractiveTimeoutError, InvalidError
|
|
14
|
+
from .io_streams import (
|
|
15
|
+
_StreamReader,
|
|
16
|
+
_StreamReaderThroughCommandRouterParams,
|
|
17
|
+
_StreamWriter,
|
|
18
|
+
_StreamWriterThroughCommandRouterParams,
|
|
19
|
+
)
|
|
20
|
+
from .stream_type import StreamType
|
|
21
|
+
|
|
22
|
+
T = TypeVar("T", str, bytes)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
async def _iter_stream_as_bytes(stream: _StreamReader[T]):
|
|
26
|
+
"""Yield raw bytes from a StreamReader regardless of text mode/backend."""
|
|
27
|
+
async for part in stream:
|
|
28
|
+
if isinstance(part, str):
|
|
29
|
+
yield part.encode("utf-8")
|
|
30
|
+
else:
|
|
31
|
+
yield part
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class _ContainerProcess(Generic[T]):
|
|
35
|
+
"""Represents a running process in a container.
|
|
36
|
+
|
|
37
|
+
Container processes communicate via direct communication with
|
|
38
|
+
the Modal worker where the container is running.
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
def __init__(
|
|
42
|
+
self,
|
|
43
|
+
process_id: str,
|
|
44
|
+
task_id: str,
|
|
45
|
+
client: _Client,
|
|
46
|
+
command_router_client: TaskCommandRouterClient,
|
|
47
|
+
stdout: StreamType = StreamType.PIPE,
|
|
48
|
+
stderr: StreamType = StreamType.PIPE,
|
|
49
|
+
exec_deadline: Optional[float] = None,
|
|
50
|
+
text: bool = True,
|
|
51
|
+
by_line: bool = False,
|
|
52
|
+
) -> None:
|
|
53
|
+
self._client = client
|
|
54
|
+
self._command_router_client = command_router_client
|
|
55
|
+
self._process_id = process_id
|
|
56
|
+
self._exec_deadline = exec_deadline
|
|
57
|
+
self._text = text
|
|
58
|
+
self._by_line = by_line
|
|
59
|
+
self._task_id = task_id
|
|
60
|
+
self._stdout = _StreamReader[T](
|
|
61
|
+
_StreamReaderThroughCommandRouterParams(
|
|
62
|
+
file_descriptor=api_pb2.FILE_DESCRIPTOR_STDOUT,
|
|
63
|
+
task_id=self._task_id,
|
|
64
|
+
object_id=process_id,
|
|
65
|
+
command_router_client=self._command_router_client,
|
|
66
|
+
deadline=exec_deadline,
|
|
67
|
+
),
|
|
68
|
+
stream_type=stdout,
|
|
69
|
+
text=text,
|
|
70
|
+
by_line=by_line,
|
|
71
|
+
)
|
|
72
|
+
self._stderr = _StreamReader[T](
|
|
73
|
+
_StreamReaderThroughCommandRouterParams(
|
|
74
|
+
file_descriptor=api_pb2.FILE_DESCRIPTOR_STDERR,
|
|
75
|
+
task_id=self._task_id,
|
|
76
|
+
object_id=process_id,
|
|
77
|
+
command_router_client=self._command_router_client,
|
|
78
|
+
deadline=exec_deadline,
|
|
79
|
+
),
|
|
80
|
+
stream_type=stderr,
|
|
81
|
+
text=text,
|
|
82
|
+
by_line=by_line,
|
|
83
|
+
)
|
|
84
|
+
self._stdin = _StreamWriter(
|
|
85
|
+
_StreamWriterThroughCommandRouterParams(
|
|
86
|
+
task_id=self._task_id,
|
|
87
|
+
object_id=process_id,
|
|
88
|
+
command_router_client=self._command_router_client,
|
|
89
|
+
)
|
|
90
|
+
)
|
|
91
|
+
self._returncode = None
|
|
92
|
+
|
|
93
|
+
def __repr__(self) -> str:
|
|
94
|
+
return f"ContainerProcess(process_id={self._process_id!r})"
|
|
95
|
+
|
|
96
|
+
@property
|
|
97
|
+
def stdout(self) -> _StreamReader[T]:
|
|
98
|
+
"""StreamReader for the container process's stdout stream."""
|
|
99
|
+
return self._stdout
|
|
100
|
+
|
|
101
|
+
@property
|
|
102
|
+
def stderr(self) -> _StreamReader[T]:
|
|
103
|
+
"""StreamReader for the container process's stderr stream."""
|
|
104
|
+
return self._stderr
|
|
105
|
+
|
|
106
|
+
@property
|
|
107
|
+
def stdin(self) -> _StreamWriter:
|
|
108
|
+
"""StreamWriter for the container process's stdin stream."""
|
|
109
|
+
return self._stdin
|
|
110
|
+
|
|
111
|
+
@property
|
|
112
|
+
def returncode(self) -> int:
|
|
113
|
+
if self._returncode is None:
|
|
114
|
+
raise InvalidError(
|
|
115
|
+
"You must call wait() before accessing the returncode. "
|
|
116
|
+
"To poll for the status of a running process, use poll() instead."
|
|
117
|
+
)
|
|
118
|
+
return self._returncode
|
|
119
|
+
|
|
120
|
+
async def poll(self) -> Optional[int]:
|
|
121
|
+
"""Check if the container process has finished running.
|
|
122
|
+
|
|
123
|
+
Returns `None` if the process is still running, else returns the exit code.
|
|
124
|
+
"""
|
|
125
|
+
if self._returncode is not None:
|
|
126
|
+
return self._returncode
|
|
127
|
+
try:
|
|
128
|
+
resp = await self._command_router_client.exec_poll(self._task_id, self._process_id, self._exec_deadline)
|
|
129
|
+
which = resp.WhichOneof("exit_status")
|
|
130
|
+
if which is None:
|
|
131
|
+
return None
|
|
132
|
+
|
|
133
|
+
if which == "code":
|
|
134
|
+
self._returncode = int(resp.code)
|
|
135
|
+
return self._returncode
|
|
136
|
+
elif which == "signal":
|
|
137
|
+
self._returncode = 128 + int(resp.signal)
|
|
138
|
+
return self._returncode
|
|
139
|
+
else:
|
|
140
|
+
logger.debug(f"ContainerProcess {self._process_id} exited with unexpected status: {which}")
|
|
141
|
+
raise InvalidError("Unexpected exit status")
|
|
142
|
+
except ExecTimeoutError:
|
|
143
|
+
logger.debug(f"ContainerProcess poll for {self._process_id} did not complete within deadline")
|
|
144
|
+
# TODO(saltzm): This is a weird API, but customers currently may rely on it. This
|
|
145
|
+
# should probably raise an ExecTimeoutError instead.
|
|
146
|
+
self._returncode = -1
|
|
147
|
+
return self._returncode
|
|
148
|
+
except Exception as e:
|
|
149
|
+
# Re-raise non-transient errors or errors resulting from exceeding retries on transient errors.
|
|
150
|
+
logger.warning(f"ContainerProcess poll for {self._process_id} failed: {e}")
|
|
151
|
+
raise
|
|
152
|
+
|
|
153
|
+
async def wait(self) -> int:
|
|
154
|
+
"""Wait for the container process to finish running. Returns the exit code."""
|
|
155
|
+
if self._returncode is not None:
|
|
156
|
+
return self._returncode
|
|
157
|
+
|
|
158
|
+
try:
|
|
159
|
+
resp = await self._command_router_client.exec_wait(self._task_id, self._process_id, self._exec_deadline)
|
|
160
|
+
which = resp.WhichOneof("exit_status")
|
|
161
|
+
if which == "code":
|
|
162
|
+
self._returncode = int(resp.code)
|
|
163
|
+
elif which == "signal":
|
|
164
|
+
self._returncode = 128 + int(resp.signal)
|
|
165
|
+
else:
|
|
166
|
+
logger.debug(f"ContainerProcess {self._process_id} exited with unexpected status: {which}")
|
|
167
|
+
self._returncode = -1
|
|
168
|
+
raise InvalidError("Unexpected exit status")
|
|
169
|
+
except ExecTimeoutError:
|
|
170
|
+
logger.debug(f"ContainerProcess {self._process_id} did not complete within deadline")
|
|
171
|
+
# TODO(saltzm): This is a weird API, but customers currently may rely on it. This
|
|
172
|
+
# should be a ExecTimeoutError.
|
|
173
|
+
self._returncode = -1
|
|
174
|
+
|
|
175
|
+
return self._returncode
|
|
176
|
+
|
|
177
|
+
async def attach(self):
|
|
178
|
+
"""mdmd:hidden"""
|
|
179
|
+
if platform.system() == "Windows":
|
|
180
|
+
print("interactive exec is not currently supported on Windows.") # noqa: T201
|
|
181
|
+
return
|
|
182
|
+
|
|
183
|
+
from .output import OutputManager
|
|
184
|
+
|
|
185
|
+
output = OutputManager.get()
|
|
186
|
+
connecting_status = output.status("Connecting...")
|
|
187
|
+
connecting_status.start()
|
|
188
|
+
on_connect = asyncio.Event()
|
|
189
|
+
|
|
190
|
+
async def _write_to_fd_loop(stream: _StreamReader[T]):
|
|
191
|
+
async for chunk in _iter_stream_as_bytes(stream):
|
|
192
|
+
if chunk is None:
|
|
193
|
+
break
|
|
194
|
+
|
|
195
|
+
if not on_connect.is_set():
|
|
196
|
+
connecting_status.stop()
|
|
197
|
+
on_connect.set()
|
|
198
|
+
|
|
199
|
+
await write_to_fd(stream.file_descriptor, chunk)
|
|
200
|
+
|
|
201
|
+
async def _handle_input(data: bytes, message_index: int):
|
|
202
|
+
self.stdin.write(data)
|
|
203
|
+
await self.stdin.drain()
|
|
204
|
+
|
|
205
|
+
async with TaskContext() as tc:
|
|
206
|
+
stdout_task = tc.create_task(_write_to_fd_loop(self.stdout))
|
|
207
|
+
stderr_task = tc.create_task(_write_to_fd_loop(self.stderr))
|
|
208
|
+
|
|
209
|
+
try:
|
|
210
|
+
# Time out if we can't connect fast enough.
|
|
211
|
+
await asyncio.wait_for(on_connect.wait(), timeout=60)
|
|
212
|
+
|
|
213
|
+
async with stream_from_stdin(_handle_input, use_raw_terminal=True):
|
|
214
|
+
await stdout_task
|
|
215
|
+
await stderr_task
|
|
216
|
+
|
|
217
|
+
except (asyncio.TimeoutError, TimeoutError):
|
|
218
|
+
connecting_status.stop()
|
|
219
|
+
stdout_task.cancel()
|
|
220
|
+
stderr_task.cancel()
|
|
221
|
+
raise InteractiveTimeoutError("Failed to establish connection to container. Please try again.")
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
ContainerProcess = synchronize_api(_ContainerProcess)
|
|
@@ -7,140 +7,27 @@ import typing_extensions
|
|
|
7
7
|
|
|
8
8
|
T = typing.TypeVar("T")
|
|
9
9
|
|
|
10
|
-
class _ContainerProcessThroughServer(typing.Generic[T]):
|
|
11
|
-
"""Abstract base class for generic types.
|
|
12
|
-
|
|
13
|
-
A generic type is typically declared by inheriting from
|
|
14
|
-
this class parameterized with one or more type variables.
|
|
15
|
-
For example, a generic mapping type might be defined as::
|
|
16
|
-
|
|
17
|
-
class Mapping(Generic[KT, VT]):
|
|
18
|
-
def __getitem__(self, key: KT) -> VT:
|
|
19
|
-
...
|
|
20
|
-
# Etc.
|
|
21
|
-
|
|
22
|
-
This class can then be used as follows::
|
|
23
|
-
|
|
24
|
-
def lookup_name(mapping: Mapping[KT, VT], key: KT, default: VT) -> VT:
|
|
25
|
-
try:
|
|
26
|
-
return mapping[key]
|
|
27
|
-
except KeyError:
|
|
28
|
-
return default
|
|
29
|
-
"""
|
|
30
|
-
|
|
31
|
-
_process_id: typing.Optional[str]
|
|
32
|
-
_stdout: modal.io_streams._StreamReader[T]
|
|
33
|
-
_stderr: modal.io_streams._StreamReader[T]
|
|
34
|
-
_stdin: modal.io_streams._StreamWriter
|
|
35
|
-
_exec_deadline: typing.Optional[float]
|
|
36
|
-
_text: bool
|
|
37
|
-
_by_line: bool
|
|
38
|
-
_returncode: typing.Optional[int]
|
|
39
|
-
|
|
40
|
-
def __init__(
|
|
41
|
-
self,
|
|
42
|
-
process_id: str,
|
|
43
|
-
task_id: str,
|
|
44
|
-
client: modal.client._Client,
|
|
45
|
-
stdout: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
|
|
46
|
-
stderr: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
|
|
47
|
-
exec_deadline: typing.Optional[float] = None,
|
|
48
|
-
text: bool = True,
|
|
49
|
-
by_line: bool = False,
|
|
50
|
-
) -> None:
|
|
51
|
-
"""Initialize self. See help(type(self)) for accurate signature."""
|
|
52
|
-
...
|
|
53
|
-
|
|
54
|
-
def __repr__(self) -> str:
|
|
55
|
-
"""Return repr(self)."""
|
|
56
|
-
...
|
|
57
|
-
|
|
58
|
-
@property
|
|
59
|
-
def stdout(self) -> modal.io_streams._StreamReader[T]:
|
|
60
|
-
"""StreamReader for the container process's stdout stream."""
|
|
61
|
-
...
|
|
62
|
-
|
|
63
|
-
@property
|
|
64
|
-
def stderr(self) -> modal.io_streams._StreamReader[T]:
|
|
65
|
-
"""StreamReader for the container process's stderr stream."""
|
|
66
|
-
...
|
|
67
|
-
|
|
68
|
-
@property
|
|
69
|
-
def stdin(self) -> modal.io_streams._StreamWriter:
|
|
70
|
-
"""StreamWriter for the container process's stdin stream."""
|
|
71
|
-
...
|
|
72
|
-
|
|
73
|
-
@property
|
|
74
|
-
def returncode(self) -> int: ...
|
|
75
|
-
async def poll(self) -> typing.Optional[int]:
|
|
76
|
-
"""Check if the container process has finished running.
|
|
77
|
-
|
|
78
|
-
Returns `None` if the process is still running, else returns the exit code.
|
|
79
|
-
"""
|
|
80
|
-
...
|
|
81
|
-
|
|
82
|
-
async def _wait_for_completion(self) -> int: ...
|
|
83
|
-
async def wait(self) -> int:
|
|
84
|
-
"""Wait for the container process to finish running. Returns the exit code."""
|
|
85
|
-
...
|
|
86
|
-
|
|
87
|
-
async def attach(self):
|
|
88
|
-
"""mdmd:hidden"""
|
|
89
|
-
...
|
|
90
|
-
|
|
91
10
|
def _iter_stream_as_bytes(stream: modal.io_streams._StreamReader[T]):
|
|
92
11
|
"""Yield raw bytes from a StreamReader regardless of text mode/backend."""
|
|
93
12
|
...
|
|
94
13
|
|
|
95
|
-
class
|
|
96
|
-
"""
|
|
14
|
+
class _ContainerProcess(typing.Generic[T]):
|
|
15
|
+
"""Represents a running process in a container.
|
|
16
|
+
|
|
17
|
+
Container processes communicate via direct communication with
|
|
97
18
|
the Modal worker where the container is running.
|
|
98
19
|
"""
|
|
99
|
-
def __init__(
|
|
100
|
-
self,
|
|
101
|
-
process_id: str,
|
|
102
|
-
client: modal.client._Client,
|
|
103
|
-
command_router_client: modal._utils.task_command_router_client.TaskCommandRouterClient,
|
|
104
|
-
task_id: str,
|
|
105
|
-
*,
|
|
106
|
-
stdout: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
|
|
107
|
-
stderr: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
|
|
108
|
-
exec_deadline: typing.Optional[float] = None,
|
|
109
|
-
text: bool = True,
|
|
110
|
-
by_line: bool = False,
|
|
111
|
-
) -> None:
|
|
112
|
-
"""Initialize self. See help(type(self)) for accurate signature."""
|
|
113
|
-
...
|
|
114
|
-
|
|
115
|
-
def __repr__(self) -> str:
|
|
116
|
-
"""Return repr(self)."""
|
|
117
|
-
...
|
|
118
|
-
|
|
119
|
-
@property
|
|
120
|
-
def stdout(self) -> modal.io_streams._StreamReader[T]: ...
|
|
121
|
-
@property
|
|
122
|
-
def stderr(self) -> modal.io_streams._StreamReader[T]: ...
|
|
123
|
-
@property
|
|
124
|
-
def stdin(self) -> modal.io_streams._StreamWriter: ...
|
|
125
|
-
@property
|
|
126
|
-
def returncode(self) -> int: ...
|
|
127
|
-
async def poll(self) -> typing.Optional[int]: ...
|
|
128
|
-
async def wait(self) -> int: ...
|
|
129
|
-
async def attach(self): ...
|
|
130
|
-
|
|
131
|
-
class _ContainerProcess(typing.Generic[T]):
|
|
132
|
-
"""Represents a running process in a container."""
|
|
133
20
|
def __init__(
|
|
134
21
|
self,
|
|
135
22
|
process_id: str,
|
|
136
23
|
task_id: str,
|
|
137
24
|
client: modal.client._Client,
|
|
25
|
+
command_router_client: modal._utils.task_command_router_client.TaskCommandRouterClient,
|
|
138
26
|
stdout: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
|
|
139
27
|
stderr: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
|
|
140
28
|
exec_deadline: typing.Optional[float] = None,
|
|
141
29
|
text: bool = True,
|
|
142
30
|
by_line: bool = False,
|
|
143
|
-
command_router_client: typing.Optional[modal._utils.task_command_router_client.TaskCommandRouterClient] = None,
|
|
144
31
|
) -> None:
|
|
145
32
|
"""Initialize self. See help(type(self)) for accurate signature."""
|
|
146
33
|
...
|
|
@@ -182,18 +69,22 @@ class _ContainerProcess(typing.Generic[T]):
|
|
|
182
69
|
...
|
|
183
70
|
|
|
184
71
|
class ContainerProcess(typing.Generic[T]):
|
|
185
|
-
"""Represents a running process in a container.
|
|
72
|
+
"""Represents a running process in a container.
|
|
73
|
+
|
|
74
|
+
Container processes communicate via direct communication with
|
|
75
|
+
the Modal worker where the container is running.
|
|
76
|
+
"""
|
|
186
77
|
def __init__(
|
|
187
78
|
self,
|
|
188
79
|
process_id: str,
|
|
189
80
|
task_id: str,
|
|
190
81
|
client: modal.client.Client,
|
|
82
|
+
command_router_client: modal._utils.task_command_router_client.TaskCommandRouterClient,
|
|
191
83
|
stdout: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
|
|
192
84
|
stderr: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
|
|
193
85
|
exec_deadline: typing.Optional[float] = None,
|
|
194
86
|
text: bool = True,
|
|
195
87
|
by_line: bool = False,
|
|
196
|
-
command_router_client: typing.Optional[modal._utils.task_command_router_client.TaskCommandRouterClient] = None,
|
|
197
88
|
) -> None: ...
|
|
198
89
|
def __repr__(self) -> str: ...
|
|
199
90
|
@property
|
|
@@ -248,7 +248,6 @@ class _FileIO(Generic[T]):
|
|
|
248
248
|
"`FileIO.read()` is deprecated."
|
|
249
249
|
" Use `Sandbox.filesystem.read_text()`, `Sandbox.filesystem.read_bytes()`,"
|
|
250
250
|
" or `Sandbox.filesystem.copy_to_local()` instead.",
|
|
251
|
-
pending=True,
|
|
252
251
|
)
|
|
253
252
|
self._check_closed()
|
|
254
253
|
self._check_readable()
|
|
@@ -266,7 +265,6 @@ class _FileIO(Generic[T]):
|
|
|
266
265
|
"`FileIO.readline()` is deprecated."
|
|
267
266
|
" Use `Sandbox.filesystem.read_text()`, `Sandbox.filesystem.read_bytes()`,"
|
|
268
267
|
" or `Sandbox.filesystem.copy_to_local()` instead.",
|
|
269
|
-
pending=True,
|
|
270
268
|
)
|
|
271
269
|
self._check_closed()
|
|
272
270
|
self._check_readable()
|
|
@@ -288,7 +286,6 @@ class _FileIO(Generic[T]):
|
|
|
288
286
|
"`FileIO.readlines()` is deprecated."
|
|
289
287
|
" Use `Sandbox.filesystem.read_text()`, `Sandbox.filesystem.read_bytes()`,"
|
|
290
288
|
" or `Sandbox.filesystem.copy_to_local()` instead.",
|
|
291
|
-
pending=True,
|
|
292
289
|
)
|
|
293
290
|
self._check_closed()
|
|
294
291
|
self._check_readable()
|
|
@@ -314,7 +311,6 @@ class _FileIO(Generic[T]):
|
|
|
314
311
|
"`FileIO.write()` is deprecated."
|
|
315
312
|
" Use `Sandbox.filesystem.write_text()`, `Sandbox.filesystem.write_bytes()`,"
|
|
316
313
|
" or `Sandbox.filesystem.copy_from_local()` instead.",
|
|
317
|
-
pending=True,
|
|
318
314
|
)
|
|
319
315
|
self._check_closed()
|
|
320
316
|
self._check_writable()
|
|
@@ -343,7 +339,6 @@ class _FileIO(Generic[T]):
|
|
|
343
339
|
"`FileIO.flush()` is deprecated."
|
|
344
340
|
" Use `Sandbox.filesystem.write_text()`, `Sandbox.filesystem.write_bytes()`,"
|
|
345
341
|
" or `Sandbox.filesystem.copy_from_local()` instead.",
|
|
346
|
-
pending=True,
|
|
347
342
|
)
|
|
348
343
|
self._check_closed()
|
|
349
344
|
self._check_writable()
|
|
@@ -407,7 +402,6 @@ class _FileIO(Generic[T]):
|
|
|
407
402
|
deprecation_warning(
|
|
408
403
|
(2026, 3, 9),
|
|
409
404
|
"`FileIO.mkdir()` is deprecated. Use `Sandbox.filesystem.make_directory()` instead.",
|
|
410
|
-
pending=True,
|
|
411
405
|
)
|
|
412
406
|
await mkdir(path, client, task_id, parents)
|
|
413
407
|
|
|
@@ -417,7 +411,6 @@ class _FileIO(Generic[T]):
|
|
|
417
411
|
deprecation_warning(
|
|
418
412
|
(2026, 3, 9),
|
|
419
413
|
"`FileIO.rm()` is deprecated. Use `Sandbox.filesystem.remove()` instead.",
|
|
420
|
-
pending=True,
|
|
421
414
|
)
|
|
422
415
|
await rm(path, client, task_id, recursive)
|
|
423
416
|
|