modal 1.4.2.dev8__tar.gz → 1.4.2.dev9__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/PKG-INFO +1 -1
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_utils/task_command_router_client.py +6 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/client.py +7 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/client.pyi +14 -2
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/functions.pyi +6 -6
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/sandbox.py +29 -7
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/sandbox.pyi +54 -21
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal.egg-info/PKG-INFO +1 -1
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal_version/__init__.py +1 -1
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/pyproject.toml +3 -3
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/LICENSE +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/README.md +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/__init__.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/__main__.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_billing.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_clustered_functions.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_clustered_functions.pyi +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_container_entrypoint.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_functions.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_grpc_client.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_ipython.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_load_context.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_location.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_logs.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_object.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_output/__init__.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_output/manager.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_output/pty.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_output/rich.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_output/status.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_partial_function.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_resolver.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_resources.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_runtime/__init__.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_runtime/asgi.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_runtime/container_io_manager.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_runtime/container_io_manager.pyi +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_runtime/execution_context.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_runtime/execution_context.pyi +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_runtime/gpu_memory_snapshot.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_runtime/telemetry.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_runtime/user_code_event_loop.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_runtime/user_code_imports.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_serialization.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_server.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_traceback.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_tunnel.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_tunnel.pyi +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_type_manager.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_utils/__init__.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_utils/app_utils.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_utils/async_utils.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_utils/auth_token_manager.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_utils/blob_utils.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_utils/browser_utils.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_utils/bytes_io_segment_payload.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_utils/deprecation.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_utils/docker_utils.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_utils/function_utils.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_utils/git_utils.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_utils/grpc_testing.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_utils/grpc_utils.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_utils/hash_utils.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_utils/http_utils.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_utils/jwt_utils.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_utils/logger.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_utils/mount_utils.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_utils/name_utils.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_utils/package_utils.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_utils/pattern_utils.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_utils/rand_pb_testing.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_utils/sandbox_fs_utils.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_utils/shell_utils.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_utils/time_utils.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_vendor/__init__.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_vendor/a2wsgi_wsgi.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_vendor/cloudpickle.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_vendor/tblib.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_vendor/version.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/_watcher.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/app.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/app.pyi +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/billing.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/builder/2023.12.312.txt +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/builder/2023.12.txt +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/builder/2024.04.txt +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/builder/2024.10.txt +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/builder/2025.06.txt +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/builder/PREVIEW.txt +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/builder/README.md +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/builder/base-images.json +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/call_graph.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/cli/__init__.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/cli/_download.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/cli/_traceback.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/cli/app.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/cli/billing.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/cli/changelog.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/cli/cluster.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/cli/config.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/cli/container.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/cli/dashboard.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/cli/dict.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/cli/entry_point.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/cli/environment.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/cli/import_refs.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/cli/launch.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/cli/network_file_system.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/cli/profile.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/cli/programs/__init__.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/cli/programs/run_jupyter.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/cli/programs/vscode.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/cli/queues.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/cli/run.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/cli/secret.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/cli/selector.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/cli/shell.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/cli/token.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/cli/utils.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/cli/volume.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/cloud_bucket_mount.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/cloud_bucket_mount.pyi +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/cls.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/cls.pyi +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/config.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/container_process.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/container_process.pyi +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/dict.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/dict.pyi +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/environments.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/environments.pyi +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/exception.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/experimental/__init__.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/experimental/flash.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/experimental/flash.pyi +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/experimental/ipython.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/file_io.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/file_io.pyi +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/file_pattern_matcher.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/functions.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/image.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/image.pyi +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/io_streams.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/io_streams.pyi +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/mount.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/mount.pyi +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/network_file_system.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/network_file_system.pyi +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/object.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/object.pyi +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/output.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/parallel_map.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/parallel_map.pyi +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/partial_function.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/partial_function.pyi +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/proxy.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/proxy.pyi +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/py.typed +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/queue.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/queue.pyi +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/retries.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/runner.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/runner.pyi +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/running_app.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/sandbox_fs.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/sandbox_fs.pyi +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/schedule.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/scheduler_placement.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/secret.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/secret.pyi +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/server.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/server.pyi +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/serving.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/serving.pyi +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/snapshot.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/snapshot.pyi +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/stream_type.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/token_flow.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/token_flow.pyi +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/volume.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal/volume.pyi +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal.egg-info/SOURCES.txt +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal.egg-info/dependency_links.txt +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal.egg-info/entry_points.txt +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal.egg-info/requires.txt +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal.egg-info/top_level.txt +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal_docs/__init__.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal_docs/gen_cli_docs.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal_docs/gen_cli_docs_main.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal_docs/gen_reference_docs.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal_docs/gen_reference_docs_main.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal_docs/mdmd/__init__.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal_docs/mdmd/mdmd.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal_docs/mdmd/signatures.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal_proto/__init__.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal_proto/api_grpc.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal_proto/api_pb2.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal_proto/api_pb2.pyi +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal_proto/api_pb2_grpc.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal_proto/api_pb2_grpc.pyi +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal_proto/modal_api_grpc.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal_proto/py.typed +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal_proto/task_command_router_grpc.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal_proto/task_command_router_pb2.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal_proto/task_command_router_pb2.pyi +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal_proto/task_command_router_pb2_grpc.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal_proto/task_command_router_pb2_grpc.pyi +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/modal_version/__main__.py +0 -0
- {modal-1.4.2.dev8 → modal-1.4.2.dev9}/setup.cfg +0 -0
|
@@ -617,6 +617,12 @@ class TaskCommandRouterClient:
|
|
|
617
617
|
lambda: self._call_with_auth_retry(self._stub.TaskMountDirectory, request)
|
|
618
618
|
)
|
|
619
619
|
|
|
620
|
+
async def unmount_image(self, request: sr_pb2.TaskUnmountDirectoryRequest):
|
|
621
|
+
with grpc_error_converter():
|
|
622
|
+
return await call_with_retries_on_transient_errors(
|
|
623
|
+
lambda: self._call_with_auth_retry(self._stub.TaskUnmountDirectory, request)
|
|
624
|
+
)
|
|
625
|
+
|
|
620
626
|
async def snapshot_directory(
|
|
621
627
|
self, request: sr_pb2.TaskSnapshotDirectoryRequest
|
|
622
628
|
) -> sr_pb2.TaskSnapshotDirectoryResponse:
|
|
@@ -239,6 +239,10 @@ class _Client:
|
|
|
239
239
|
"""
|
|
240
240
|
Constructor based on token credentials; useful for managing Modal on behalf of third-party users.
|
|
241
241
|
|
|
242
|
+
Also useful when it's necessary to explicitly manage the lifecycle of the client
|
|
243
|
+
(e.g. when running Modal in a forked subprocess) — see
|
|
244
|
+
[troubleshooting](/docs/guide/troubleshooting#connection-issues-in-forked-processes).
|
|
245
|
+
|
|
242
246
|
**Usage:**
|
|
243
247
|
|
|
244
248
|
```python notest
|
|
@@ -309,6 +313,9 @@ class _Client:
|
|
|
309
313
|
return await coro
|
|
310
314
|
|
|
311
315
|
async def _reset_on_pid_change(self):
|
|
316
|
+
# Best-effort recovery after os.fork(). The client singleton may be inherited
|
|
317
|
+
# from the parent with stale gRPC state. For reliable post-fork usage, create
|
|
318
|
+
# a fresh client via Client.from_credentials() instead of relying on this.
|
|
312
319
|
if self._owner_pid and self._owner_pid != os.getpid():
|
|
313
320
|
# not calling .close() since that would also interact with stale resources
|
|
314
321
|
# just reset the internal state
|
|
@@ -35,7 +35,7 @@ class _Client:
|
|
|
35
35
|
server_url: str,
|
|
36
36
|
client_type: int,
|
|
37
37
|
credentials: typing.Optional[tuple[str, str]],
|
|
38
|
-
version: str = "1.4.2.
|
|
38
|
+
version: str = "1.4.2.dev9",
|
|
39
39
|
):
|
|
40
40
|
"""mdmd:hidden
|
|
41
41
|
The Modal client object is not intended to be instantiated directly by users.
|
|
@@ -97,6 +97,10 @@ class _Client:
|
|
|
97
97
|
async def from_credentials(cls, token_id: str, token_secret: str) -> _Client:
|
|
98
98
|
"""Constructor based on token credentials; useful for managing Modal on behalf of third-party users.
|
|
99
99
|
|
|
100
|
+
Also useful when it's necessary to explicitly manage the lifecycle of the client
|
|
101
|
+
(e.g. when running Modal in a forked subprocess) — see
|
|
102
|
+
[troubleshooting](/docs/guide/troubleshooting#connection-issues-in-forked-processes).
|
|
103
|
+
|
|
100
104
|
**Usage:**
|
|
101
105
|
|
|
102
106
|
```python notest
|
|
@@ -171,7 +175,7 @@ class Client:
|
|
|
171
175
|
server_url: str,
|
|
172
176
|
client_type: int,
|
|
173
177
|
credentials: typing.Optional[tuple[str, str]],
|
|
174
|
-
version: str = "1.4.2.
|
|
178
|
+
version: str = "1.4.2.dev9",
|
|
175
179
|
):
|
|
176
180
|
"""mdmd:hidden
|
|
177
181
|
The Modal client object is not intended to be instantiated directly by users.
|
|
@@ -283,6 +287,10 @@ class Client:
|
|
|
283
287
|
def __call__(self, /, token_id: str, token_secret: str) -> Client:
|
|
284
288
|
"""Constructor based on token credentials; useful for managing Modal on behalf of third-party users.
|
|
285
289
|
|
|
290
|
+
Also useful when it's necessary to explicitly manage the lifecycle of the client
|
|
291
|
+
(e.g. when running Modal in a forked subprocess) — see
|
|
292
|
+
[troubleshooting](/docs/guide/troubleshooting#connection-issues-in-forked-processes).
|
|
293
|
+
|
|
286
294
|
**Usage:**
|
|
287
295
|
|
|
288
296
|
```python notest
|
|
@@ -296,6 +304,10 @@ class Client:
|
|
|
296
304
|
async def aio(self, /, token_id: str, token_secret: str) -> Client:
|
|
297
305
|
"""Constructor based on token credentials; useful for managing Modal on behalf of third-party users.
|
|
298
306
|
|
|
307
|
+
Also useful when it's necessary to explicitly manage the lifecycle of the client
|
|
308
|
+
(e.g. when running Modal in a forked subprocess) — see
|
|
309
|
+
[troubleshooting](/docs/guide/troubleshooting#connection-issues-in-forked-processes).
|
|
310
|
+
|
|
299
311
|
**Usage:**
|
|
300
312
|
|
|
301
313
|
```python notest
|
|
@@ -348,7 +348,7 @@ class Function(
|
|
|
348
348
|
|
|
349
349
|
_call_generator: ___call_generator_spec
|
|
350
350
|
|
|
351
|
-
class __remote_spec(typing_extensions.Protocol[
|
|
351
|
+
class __remote_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER]):
|
|
352
352
|
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> ReturnType_INNER:
|
|
353
353
|
"""Calls the function remotely, executing it with the given arguments and returning the execution's result."""
|
|
354
354
|
...
|
|
@@ -357,7 +357,7 @@ class Function(
|
|
|
357
357
|
"""Calls the function remotely, executing it with the given arguments and returning the execution's result."""
|
|
358
358
|
...
|
|
359
359
|
|
|
360
|
-
remote: __remote_spec[modal._functions.
|
|
360
|
+
remote: __remote_spec[modal._functions.P, modal._functions.ReturnType]
|
|
361
361
|
|
|
362
362
|
class __remote_gen_spec(typing_extensions.Protocol):
|
|
363
363
|
def __call__(self, /, *args, **kwargs) -> typing.Generator[typing.Any, None, None]:
|
|
@@ -384,7 +384,7 @@ class Function(
|
|
|
384
384
|
"""
|
|
385
385
|
...
|
|
386
386
|
|
|
387
|
-
class ___experimental_spawn_spec(typing_extensions.Protocol[
|
|
387
|
+
class ___experimental_spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER]):
|
|
388
388
|
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
|
|
389
389
|
"""[Experimental] Calls the function with the given arguments, without waiting for the results.
|
|
390
390
|
|
|
@@ -407,7 +407,7 @@ class Function(
|
|
|
407
407
|
"""
|
|
408
408
|
...
|
|
409
409
|
|
|
410
|
-
_experimental_spawn: ___experimental_spawn_spec[modal._functions.
|
|
410
|
+
_experimental_spawn: ___experimental_spawn_spec[modal._functions.P, modal._functions.ReturnType]
|
|
411
411
|
|
|
412
412
|
class ___spawn_map_inner_spec(typing_extensions.Protocol[P_INNER]):
|
|
413
413
|
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> None: ...
|
|
@@ -415,7 +415,7 @@ class Function(
|
|
|
415
415
|
|
|
416
416
|
_spawn_map_inner: ___spawn_map_inner_spec[modal._functions.P]
|
|
417
417
|
|
|
418
|
-
class __spawn_spec(typing_extensions.Protocol[
|
|
418
|
+
class __spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER]):
|
|
419
419
|
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
|
|
420
420
|
"""Calls the function with the given arguments, without waiting for the results.
|
|
421
421
|
|
|
@@ -436,7 +436,7 @@ class Function(
|
|
|
436
436
|
"""
|
|
437
437
|
...
|
|
438
438
|
|
|
439
|
-
spawn: __spawn_spec[modal._functions.
|
|
439
|
+
spawn: __spawn_spec[modal._functions.P, modal._functions.ReturnType]
|
|
440
440
|
|
|
441
441
|
def get_raw_f(self) -> collections.abc.Callable[..., typing.Any]:
|
|
442
442
|
"""Return the inner Python object wrapped by this Modal Function."""
|
|
@@ -923,14 +923,15 @@ class _Sandbox(_Object, type_prefix="sb"):
|
|
|
923
923
|
async def mount_image(self, path: Union[PurePosixPath, str], image: _Image):
|
|
924
924
|
"""Mount an Image at a specified path in a running Sandbox.
|
|
925
925
|
|
|
926
|
-
`path` should be a directory
|
|
927
|
-
data, the previous directory will be replaced
|
|
926
|
+
`path` should be a directory that is **not** the root path (`/`). If the path doesn't exist
|
|
927
|
+
it will be created. If it exists and contains data, the previous directory will be replaced
|
|
928
|
+
by the mount.
|
|
928
929
|
|
|
929
|
-
The `image` argument
|
|
930
|
-
-
|
|
931
|
-
- referenced by
|
|
932
|
-
-
|
|
933
|
-
|
|
930
|
+
The `image` argument supports any Image that has an object ID, including:
|
|
931
|
+
- Images built using `image.build()`
|
|
932
|
+
- Images referenced by ID, e.g. `Image.from_id(...)`
|
|
933
|
+
- Filesystem/directory snapshots, e.g. created by `.snapshot_directory()` or `.snapshot_filesystem()`
|
|
934
|
+
- Empty images created with `Image.from_scratch()`
|
|
934
935
|
|
|
935
936
|
Usage:
|
|
936
937
|
```py notest
|
|
@@ -982,6 +983,27 @@ class _Sandbox(_Object, type_prefix="sb"):
|
|
|
982
983
|
req = sr_pb2.TaskMountDirectoryRequest(task_id=task_id, path=path_bytes, image_id=image_id)
|
|
983
984
|
await command_router_client.mount_image(req)
|
|
984
985
|
|
|
986
|
+
async def unmount_image(self, path: Union[PurePosixPath, str]):
|
|
987
|
+
"""Unmount a previously mounted Image from a running Sandbox.
|
|
988
|
+
|
|
989
|
+
`path` must be the exact mount point that was passed to `.mount_image()`.
|
|
990
|
+
After unmounting, the underlying Sandbox filesystem at that path becomes
|
|
991
|
+
visible again.
|
|
992
|
+
"""
|
|
993
|
+
self._ensure_v1("unmount_image")
|
|
994
|
+
|
|
995
|
+
task_id = await self._get_task_id()
|
|
996
|
+
if (command_router_client := await self._get_command_router_client(task_id)) is None:
|
|
997
|
+
raise InvalidError("Unmounting directories requires direct Sandbox control - please contact Modal support.")
|
|
998
|
+
|
|
999
|
+
posix_path = PurePosixPath(path)
|
|
1000
|
+
if not posix_path.is_absolute():
|
|
1001
|
+
raise InvalidError(f"Unmount path must be absolute; got: {posix_path}")
|
|
1002
|
+
path_bytes = posix_path.as_posix().encode("utf8")
|
|
1003
|
+
|
|
1004
|
+
req = sr_pb2.TaskUnmountDirectoryRequest(task_id=task_id, path=path_bytes)
|
|
1005
|
+
await command_router_client.unmount_image(req)
|
|
1006
|
+
|
|
985
1007
|
async def snapshot_directory(self, path: Union[PurePosixPath, str]) -> _Image:
|
|
986
1008
|
"""Snapshot a directory in a running Sandbox, creating a new Image with its content.
|
|
987
1009
|
|
|
@@ -384,14 +384,15 @@ class _Sandbox(modal._object._Object):
|
|
|
384
384
|
async def mount_image(self, path: typing.Union[pathlib.PurePosixPath, str], image: modal.image._Image):
|
|
385
385
|
"""Mount an Image at a specified path in a running Sandbox.
|
|
386
386
|
|
|
387
|
-
`path` should be a directory
|
|
388
|
-
data, the previous directory will be replaced
|
|
387
|
+
`path` should be a directory that is **not** the root path (`/`). If the path doesn't exist
|
|
388
|
+
it will be created. If it exists and contains data, the previous directory will be replaced
|
|
389
|
+
by the mount.
|
|
389
390
|
|
|
390
|
-
The `image` argument
|
|
391
|
-
-
|
|
392
|
-
- referenced by
|
|
393
|
-
-
|
|
394
|
-
|
|
391
|
+
The `image` argument supports any Image that has an object ID, including:
|
|
392
|
+
- Images built using `image.build()`
|
|
393
|
+
- Images referenced by ID, e.g. `Image.from_id(...)`
|
|
394
|
+
- Filesystem/directory snapshots, e.g. created by `.snapshot_directory()` or `.snapshot_filesystem()`
|
|
395
|
+
- Empty images created with `Image.from_scratch()`
|
|
395
396
|
|
|
396
397
|
Usage:
|
|
397
398
|
```py notest
|
|
@@ -405,6 +406,15 @@ class _Sandbox(modal._object._Object):
|
|
|
405
406
|
"""
|
|
406
407
|
...
|
|
407
408
|
|
|
409
|
+
async def unmount_image(self, path: typing.Union[pathlib.PurePosixPath, str]):
|
|
410
|
+
"""Unmount a previously mounted Image from a running Sandbox.
|
|
411
|
+
|
|
412
|
+
`path` must be the exact mount point that was passed to `.mount_image()`.
|
|
413
|
+
After unmounting, the underlying Sandbox filesystem at that path becomes
|
|
414
|
+
visible again.
|
|
415
|
+
"""
|
|
416
|
+
...
|
|
417
|
+
|
|
408
418
|
async def snapshot_directory(self, path: typing.Union[pathlib.PurePosixPath, str]) -> modal.image._Image:
|
|
409
419
|
"""Snapshot a directory in a running Sandbox, creating a new Image with its content.
|
|
410
420
|
|
|
@@ -1351,14 +1361,15 @@ class Sandbox(modal.object.Object):
|
|
|
1351
1361
|
def __call__(self, /, path: typing.Union[pathlib.PurePosixPath, str], image: modal.image.Image):
|
|
1352
1362
|
"""Mount an Image at a specified path in a running Sandbox.
|
|
1353
1363
|
|
|
1354
|
-
`path` should be a directory
|
|
1355
|
-
data, the previous directory will be replaced
|
|
1364
|
+
`path` should be a directory that is **not** the root path (`/`). If the path doesn't exist
|
|
1365
|
+
it will be created. If it exists and contains data, the previous directory will be replaced
|
|
1366
|
+
by the mount.
|
|
1356
1367
|
|
|
1357
|
-
The `image` argument
|
|
1358
|
-
-
|
|
1359
|
-
- referenced by
|
|
1360
|
-
-
|
|
1361
|
-
|
|
1368
|
+
The `image` argument supports any Image that has an object ID, including:
|
|
1369
|
+
- Images built using `image.build()`
|
|
1370
|
+
- Images referenced by ID, e.g. `Image.from_id(...)`
|
|
1371
|
+
- Filesystem/directory snapshots, e.g. created by `.snapshot_directory()` or `.snapshot_filesystem()`
|
|
1372
|
+
- Empty images created with `Image.from_scratch()`
|
|
1362
1373
|
|
|
1363
1374
|
Usage:
|
|
1364
1375
|
```py notest
|
|
@@ -1375,14 +1386,15 @@ class Sandbox(modal.object.Object):
|
|
|
1375
1386
|
async def aio(self, /, path: typing.Union[pathlib.PurePosixPath, str], image: modal.image.Image):
|
|
1376
1387
|
"""Mount an Image at a specified path in a running Sandbox.
|
|
1377
1388
|
|
|
1378
|
-
`path` should be a directory
|
|
1379
|
-
data, the previous directory will be replaced
|
|
1389
|
+
`path` should be a directory that is **not** the root path (`/`). If the path doesn't exist
|
|
1390
|
+
it will be created. If it exists and contains data, the previous directory will be replaced
|
|
1391
|
+
by the mount.
|
|
1380
1392
|
|
|
1381
|
-
The `image` argument
|
|
1382
|
-
-
|
|
1383
|
-
- referenced by
|
|
1384
|
-
-
|
|
1385
|
-
|
|
1393
|
+
The `image` argument supports any Image that has an object ID, including:
|
|
1394
|
+
- Images built using `image.build()`
|
|
1395
|
+
- Images referenced by ID, e.g. `Image.from_id(...)`
|
|
1396
|
+
- Filesystem/directory snapshots, e.g. created by `.snapshot_directory()` or `.snapshot_filesystem()`
|
|
1397
|
+
- Empty images created with `Image.from_scratch()`
|
|
1386
1398
|
|
|
1387
1399
|
Usage:
|
|
1388
1400
|
```py notest
|
|
@@ -1398,6 +1410,27 @@ class Sandbox(modal.object.Object):
|
|
|
1398
1410
|
|
|
1399
1411
|
mount_image: __mount_image_spec
|
|
1400
1412
|
|
|
1413
|
+
class __unmount_image_spec(typing_extensions.Protocol):
|
|
1414
|
+
def __call__(self, /, path: typing.Union[pathlib.PurePosixPath, str]):
|
|
1415
|
+
"""Unmount a previously mounted Image from a running Sandbox.
|
|
1416
|
+
|
|
1417
|
+
`path` must be the exact mount point that was passed to `.mount_image()`.
|
|
1418
|
+
After unmounting, the underlying Sandbox filesystem at that path becomes
|
|
1419
|
+
visible again.
|
|
1420
|
+
"""
|
|
1421
|
+
...
|
|
1422
|
+
|
|
1423
|
+
async def aio(self, /, path: typing.Union[pathlib.PurePosixPath, str]):
|
|
1424
|
+
"""Unmount a previously mounted Image from a running Sandbox.
|
|
1425
|
+
|
|
1426
|
+
`path` must be the exact mount point that was passed to `.mount_image()`.
|
|
1427
|
+
After unmounting, the underlying Sandbox filesystem at that path becomes
|
|
1428
|
+
visible again.
|
|
1429
|
+
"""
|
|
1430
|
+
...
|
|
1431
|
+
|
|
1432
|
+
unmount_image: __unmount_image_spec
|
|
1433
|
+
|
|
1401
1434
|
class __snapshot_directory_spec(typing_extensions.Protocol):
|
|
1402
1435
|
def __call__(self, /, path: typing.Union[pathlib.PurePosixPath, str]) -> modal.image.Image:
|
|
1403
1436
|
"""Snapshot a directory in a running Sandbox, creating a new Image with its content.
|
|
@@ -50,7 +50,7 @@ dev = [
|
|
|
50
50
|
"mypy~=1.18.2",
|
|
51
51
|
"packaging>=23.1",
|
|
52
52
|
"pytest~=8.4.0",
|
|
53
|
-
"pytest-asyncio
|
|
53
|
+
"pytest-asyncio~=1.3.0",
|
|
54
54
|
"pytest-env~=1.1.5",
|
|
55
55
|
"pytest-markdown-docs==0.9.1",
|
|
56
56
|
"pytest-timeout~=2.4.0",
|
|
@@ -119,6 +119,8 @@ module = [
|
|
|
119
119
|
ignore_errors = true
|
|
120
120
|
|
|
121
121
|
[tool.pytest.ini_options]
|
|
122
|
+
asyncio_default_fixture_loop_scope = "session"
|
|
123
|
+
asyncio_default_test_loop_scope = "session"
|
|
122
124
|
timeout = 300
|
|
123
125
|
addopts = "--ignore=modal/cli/programs"
|
|
124
126
|
filterwarnings = [
|
|
@@ -126,9 +128,7 @@ filterwarnings = [
|
|
|
126
128
|
"ignore:Type google._upb.*MapContainer uses PyType_Spec.*Python 3.14:DeprecationWarning",
|
|
127
129
|
"error::modal.exception.DeprecationError",
|
|
128
130
|
"error::modal.exception.AsyncUsageWarning",
|
|
129
|
-
"ignore:There is no current event loop:DeprecationWarning", # pytest-asyncio internals
|
|
130
131
|
"ignore:distutils Version classes are deprecated:DeprecationWarning", # pytest-freezegun internals
|
|
131
|
-
"ignore:'asyncio.iscoroutinefunction' is deprecated:DeprecationWarning", # pytest-asyncio internals
|
|
132
132
|
]
|
|
133
133
|
|
|
134
134
|
[tool.ruff]
|
|
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
|
|
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
|
|
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
|
|
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
|