modal 1.2.5.dev4__tar.gz → 1.2.7.dev11__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.
Potentially problematic release.
This version of modal might be problematic. Click here for more details.
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/PKG-INFO +3 -3
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/README.md +1 -1
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/__init__.py +2 -2
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/__main__.py +4 -29
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_container_entrypoint.py +0 -1
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_functions.py +11 -17
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_grpc_client.py +48 -28
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_output.py +10 -11
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_partial_function.py +2 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_runtime/container_io_manager.py +5 -6
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_runtime/gpu_memory_snapshot.py +9 -7
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_runtime/user_code_imports.py +105 -79
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_traceback.py +1 -1
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_tunnel.py +5 -9
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_utils/blob_utils.py +23 -9
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_utils/function_utils.py +17 -21
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_utils/grpc_utils.py +5 -8
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_utils/package_utils.py +0 -1
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_utils/task_command_router_client.py +130 -129
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/app.py +62 -11
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/app.pyi +8 -4
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/cli/entry_point.py +23 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/cli/environment.py +2 -16
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/cli/launch.py +0 -74
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/cli/network_file_system.py +4 -16
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/cli/run.py +1 -1
- modal-1.2.7.dev11/modal/cli/shell.py +375 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/cli/utils.py +1 -13
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/cli/volume.py +4 -16
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/client.pyi +2 -2
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/cls.py +0 -6
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/container_process.py +2 -2
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/dict.py +44 -15
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/dict.pyi +2 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/exception.py +146 -16
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/experimental/__init__.py +8 -2
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/experimental/flash.py +132 -16
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/experimental/flash.pyi +60 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/file_io.py +39 -67
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/file_io.pyi +12 -27
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/functions.pyi +2 -1
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/image.py +17 -14
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/io_streams.py +100 -124
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/io_streams.pyi +28 -26
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/mount.py +23 -19
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/mount.pyi +3 -3
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/queue.py +12 -14
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/runner.py +2 -9
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/sandbox.py +50 -27
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/sandbox.pyi +39 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/secret.py +4 -20
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/volume.py +19 -18
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal.egg-info/PKG-INFO +3 -3
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal.egg-info/SOURCES.txt +0 -8
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal_proto/api.proto +24 -4
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal_proto/api_pb2.py +662 -656
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal_proto/api_pb2.pyi +37 -8
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal_proto/task_command_router.proto +20 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal_proto/task_command_router_grpc.py +33 -0
- modal-1.2.7.dev11/modal_proto/task_command_router_pb2.py +180 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal_proto/task_command_router_pb2.pyi +51 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal_proto/task_command_router_pb2_grpc.py +69 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal_proto/task_command_router_pb2_grpc.pyi +25 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal_version/__init__.py +1 -1
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal_version/__main__.py +1 -1
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/pyproject.toml +13 -6
- modal-1.2.5.dev4/modal/cli/programs/launch_instance_ssh.py +0 -94
- modal-1.2.5.dev4/modal/cli/programs/run_marimo.py +0 -95
- modal-1.2.5.dev4/modal/cli/shell.py +0 -237
- modal-1.2.5.dev4/modal_proto/sandbox_router.proto +0 -145
- modal-1.2.5.dev4/modal_proto/sandbox_router_grpc.py +0 -105
- modal-1.2.5.dev4/modal_proto/sandbox_router_pb2.py +0 -149
- modal-1.2.5.dev4/modal_proto/sandbox_router_pb2.pyi +0 -333
- modal-1.2.5.dev4/modal_proto/sandbox_router_pb2_grpc.py +0 -203
- modal-1.2.5.dev4/modal_proto/sandbox_router_pb2_grpc.pyi +0 -75
- modal-1.2.5.dev4/modal_proto/task_command_router_pb2.py +0 -149
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/LICENSE +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_billing.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_clustered_functions.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_clustered_functions.pyi +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_ipython.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_load_context.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_location.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_object.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_pty.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_resolver.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_resources.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_runtime/__init__.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_runtime/asgi.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_runtime/container_io_manager.pyi +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_runtime/execution_context.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_runtime/execution_context.pyi +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_runtime/telemetry.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_runtime/user_code_event_loop.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_serialization.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_tunnel.pyi +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_type_manager.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_utils/__init__.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_utils/app_utils.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_utils/async_utils.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_utils/auth_token_manager.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_utils/bytes_io_segment_payload.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_utils/deprecation.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_utils/docker_utils.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_utils/git_utils.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_utils/grpc_testing.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_utils/hash_utils.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_utils/http_utils.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_utils/jwt_utils.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_utils/logger.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_utils/mount_utils.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_utils/name_utils.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_utils/pattern_utils.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_utils/rand_pb_testing.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_utils/shell_utils.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_utils/time_utils.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_vendor/__init__.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_vendor/a2wsgi_wsgi.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_vendor/cloudpickle.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_vendor/tblib.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/_watcher.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/billing.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/builder/2023.12.312.txt +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/builder/2023.12.txt +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/builder/2024.04.txt +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/builder/2024.10.txt +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/builder/2025.06.txt +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/builder/PREVIEW.txt +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/builder/README.md +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/builder/base-images.json +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/call_graph.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/cli/__init__.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/cli/_download.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/cli/_traceback.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/cli/app.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/cli/cluster.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/cli/config.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/cli/container.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/cli/dict.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/cli/import_refs.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/cli/profile.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/cli/programs/__init__.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/cli/programs/run_jupyter.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/cli/programs/vscode.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/cli/queues.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/cli/secret.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/cli/token.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/client.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/cloud_bucket_mount.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/cloud_bucket_mount.pyi +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/cls.pyi +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/config.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/container_process.pyi +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/environments.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/environments.pyi +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/experimental/ipython.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/file_pattern_matcher.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/functions.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/gpu.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/image.pyi +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/network_file_system.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/network_file_system.pyi +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/object.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/object.pyi +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/output.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/parallel_map.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/parallel_map.pyi +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/partial_function.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/partial_function.pyi +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/proxy.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/proxy.pyi +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/py.typed +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/queue.pyi +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/retries.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/runner.pyi +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/running_app.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/schedule.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/scheduler_placement.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/secret.pyi +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/serving.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/serving.pyi +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/snapshot.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/snapshot.pyi +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/stream_type.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/token_flow.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/token_flow.pyi +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal/volume.pyi +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal.egg-info/dependency_links.txt +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal.egg-info/entry_points.txt +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal.egg-info/requires.txt +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal.egg-info/top_level.txt +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal_docs/__init__.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal_docs/gen_cli_docs.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal_docs/gen_reference_docs.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal_docs/mdmd/__init__.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal_docs/mdmd/mdmd.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal_docs/mdmd/signatures.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal_proto/__init__.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal_proto/api_grpc.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal_proto/api_pb2_grpc.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal_proto/api_pb2_grpc.pyi +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal_proto/modal_api_grpc.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/modal_proto/py.typed +0 -0
- {modal-1.2.5.dev4 → modal-1.2.7.dev11}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: modal
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.7.dev11
|
|
4
4
|
Summary: Python client library for Modal
|
|
5
5
|
Author-email: Modal Labs <support@modal.com>
|
|
6
6
|
License: Apache-2.0
|
|
@@ -13,7 +13,7 @@ Classifier: Topic :: System :: Distributed Computing
|
|
|
13
13
|
Classifier: Operating System :: OS Independent
|
|
14
14
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
15
15
|
Classifier: Programming Language :: Python :: 3
|
|
16
|
-
Requires-Python: <3.14,>=3.
|
|
16
|
+
Requires-Python: <3.14,>=3.10
|
|
17
17
|
Description-Content-Type: text/markdown
|
|
18
18
|
License-File: LICENSE
|
|
19
19
|
Requires-Dist: aiohttp
|
|
@@ -51,7 +51,7 @@ a [user guide](https://modal.com/docs/guide), and the detailed
|
|
|
51
51
|
|
|
52
52
|
## Installation
|
|
53
53
|
|
|
54
|
-
**This library requires Python 3.
|
|
54
|
+
**This library requires Python 3.10 – 3.13.**
|
|
55
55
|
|
|
56
56
|
Install the package with `uv` or `pip`:
|
|
57
57
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Copyright Modal Labs 2022
|
|
2
2
|
import sys
|
|
3
3
|
|
|
4
|
-
if sys.version_info[:2] < (3,
|
|
5
|
-
raise RuntimeError("This version of Modal requires at least Python 3.
|
|
4
|
+
if sys.version_info[:2] < (3, 10):
|
|
5
|
+
raise RuntimeError("This version of Modal requires at least Python 3.10")
|
|
6
6
|
if sys.version_info[:2] >= (3, 14):
|
|
7
7
|
raise RuntimeError("This version of Modal does not support Python 3.14+")
|
|
8
8
|
|
|
@@ -35,37 +35,12 @@ def main():
|
|
|
35
35
|
):
|
|
36
36
|
raise
|
|
37
37
|
|
|
38
|
-
from grpclib import GRPCError, Status
|
|
39
38
|
from rich.panel import Panel
|
|
40
39
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
Status.CANCELLED: "Cancelled",
|
|
46
|
-
Status.DATA_LOSS: "Data loss",
|
|
47
|
-
Status.DEADLINE_EXCEEDED: "Deadline exceeded",
|
|
48
|
-
Status.FAILED_PRECONDITION: "Failed precondition",
|
|
49
|
-
Status.INTERNAL: "Internal",
|
|
50
|
-
Status.INVALID_ARGUMENT: "Invalid",
|
|
51
|
-
Status.NOT_FOUND: "Not found",
|
|
52
|
-
Status.OUT_OF_RANGE: "Out of range",
|
|
53
|
-
Status.PERMISSION_DENIED: "Permission denied",
|
|
54
|
-
Status.RESOURCE_EXHAUSTED: "Resource exhausted",
|
|
55
|
-
Status.UNAUTHENTICATED: "Unauthenticaed",
|
|
56
|
-
Status.UNAVAILABLE: "Unavailable",
|
|
57
|
-
Status.UNIMPLEMENTED: "Unimplemented",
|
|
58
|
-
Status.UNKNOWN: "Unknown",
|
|
59
|
-
}
|
|
60
|
-
title = f"Error: {status_map.get(exc.status, 'Unknown')}"
|
|
61
|
-
content = str(exc.message)
|
|
62
|
-
if exc.details:
|
|
63
|
-
content += f"\n\nDetails: {exc.details}"
|
|
64
|
-
else:
|
|
65
|
-
title = "Error"
|
|
66
|
-
content = str(exc)
|
|
67
|
-
if notes := getattr(exc, "__notes__", []):
|
|
68
|
-
content = f"{content}\n\nNote: {' '.join(notes)}"
|
|
40
|
+
title = "Error"
|
|
41
|
+
content = str(exc)
|
|
42
|
+
if notes := getattr(exc, "__notes__", []):
|
|
43
|
+
content = f"{content}\n\nNote: {' '.join(notes)}"
|
|
69
44
|
|
|
70
45
|
console = make_console(stderr=True)
|
|
71
46
|
panel = Panel(content, title=title, title_align="left", border_style="red")
|
|
@@ -13,7 +13,7 @@ from typing import TYPE_CHECKING, Any, AsyncIterator, Callable, Optional, Union
|
|
|
13
13
|
|
|
14
14
|
import typing_extensions
|
|
15
15
|
from google.protobuf.message import Message
|
|
16
|
-
from grpclib import
|
|
16
|
+
from grpclib import Status
|
|
17
17
|
from synchronicity.combined_types import MethodWithAio
|
|
18
18
|
|
|
19
19
|
from modal_proto import api_pb2
|
|
@@ -694,13 +694,14 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
|
|
|
694
694
|
# Experimental: Clustered functions
|
|
695
695
|
cluster_size: Optional[int] = None,
|
|
696
696
|
rdma: Optional[bool] = None,
|
|
697
|
-
|
|
697
|
+
single_use_containers: bool = False,
|
|
698
698
|
ephemeral_disk: Optional[int] = None,
|
|
699
699
|
include_source: bool = True,
|
|
700
700
|
experimental_options: Optional[dict[str, str]] = None,
|
|
701
701
|
_experimental_proxy_ip: Optional[str] = None,
|
|
702
702
|
_experimental_custom_scaling_factor: Optional[float] = None,
|
|
703
703
|
restrict_output: bool = False,
|
|
704
|
+
http_config: Optional[api_pb2.HTTPConfig] = None,
|
|
704
705
|
) -> "_Function":
|
|
705
706
|
"""mdmd:hidden
|
|
706
707
|
|
|
@@ -809,14 +810,6 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
|
|
|
809
810
|
if arg.default is not inspect.Parameter.empty:
|
|
810
811
|
raise InvalidError(f"Modal batched function {func_name} does not accept default arguments.")
|
|
811
812
|
|
|
812
|
-
if max_inputs is not None:
|
|
813
|
-
if not isinstance(max_inputs, int):
|
|
814
|
-
raise InvalidError(f"`max_inputs` must be an int, not {type(max_inputs).__name__}")
|
|
815
|
-
if max_inputs <= 0:
|
|
816
|
-
raise InvalidError("`max_inputs` must be positive")
|
|
817
|
-
if max_inputs > 1:
|
|
818
|
-
raise InvalidError("Only `max_inputs=1` is currently supported")
|
|
819
|
-
|
|
820
813
|
# Validate volumes
|
|
821
814
|
validated_volumes = validate_volumes(volumes)
|
|
822
815
|
cloud_bucket_mounts = [(k, v) for k, v in validated_volumes if isinstance(v, _CloudBucketMount)]
|
|
@@ -987,6 +980,7 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
|
|
|
987
980
|
function_definition = api_pb2.Function(
|
|
988
981
|
module_name=info.module_name or "",
|
|
989
982
|
function_name=info.function_name,
|
|
983
|
+
implementation_name=info.implementation_name,
|
|
990
984
|
mount_ids=loaded_mount_ids,
|
|
991
985
|
secret_ids=[secret.object_id for secret in secrets],
|
|
992
986
|
image_id=(image.object_id if image else ""),
|
|
@@ -1022,7 +1016,8 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
|
|
|
1022
1016
|
object_dependencies=object_dependencies,
|
|
1023
1017
|
block_network=block_network,
|
|
1024
1018
|
untrusted=restrict_modal_access,
|
|
1025
|
-
|
|
1019
|
+
single_use_containers=single_use_containers,
|
|
1020
|
+
max_inputs=int(single_use_containers), # TODO(michael) remove after worker rollover
|
|
1026
1021
|
cloud_bucket_mounts=cloud_bucket_mounts_to_proto(cloud_bucket_mounts),
|
|
1027
1022
|
scheduler_placement=scheduler_placement,
|
|
1028
1023
|
is_class=info.is_service_class(),
|
|
@@ -1046,12 +1041,14 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
|
|
|
1046
1041
|
function_schema=function_schema,
|
|
1047
1042
|
supported_input_formats=supported_input_formats,
|
|
1048
1043
|
supported_output_formats=supported_output_formats,
|
|
1044
|
+
http_config=http_config,
|
|
1049
1045
|
)
|
|
1050
1046
|
|
|
1051
1047
|
if isinstance(gpu, list):
|
|
1052
1048
|
function_data = api_pb2.FunctionData(
|
|
1053
1049
|
module_name=function_definition.module_name,
|
|
1054
1050
|
function_name=function_definition.function_name,
|
|
1051
|
+
implementation_name=function_definition.implementation_name,
|
|
1055
1052
|
function_type=function_definition.function_type,
|
|
1056
1053
|
warm_pool_size=function_definition.warm_pool_size,
|
|
1057
1054
|
concurrency_limit=function_definition.concurrency_limit,
|
|
@@ -1083,6 +1080,7 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
|
|
|
1083
1080
|
untrusted=function_definition.untrusted,
|
|
1084
1081
|
supported_input_formats=supported_input_formats,
|
|
1085
1082
|
supported_output_formats=supported_output_formats,
|
|
1083
|
+
http_config=http_config,
|
|
1086
1084
|
)
|
|
1087
1085
|
|
|
1088
1086
|
ranked_functions = []
|
|
@@ -1121,12 +1119,8 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
|
|
|
1121
1119
|
)
|
|
1122
1120
|
try:
|
|
1123
1121
|
response: api_pb2.FunctionCreateResponse = await load_context.client.stub.FunctionCreate(request)
|
|
1124
|
-
except
|
|
1125
|
-
if
|
|
1126
|
-
raise InvalidError(exc.message)
|
|
1127
|
-
if exc.status == Status.FAILED_PRECONDITION:
|
|
1128
|
-
raise InvalidError(exc.message)
|
|
1129
|
-
if exc.message and "Received :status = '413'" in exc.message:
|
|
1122
|
+
except Exception as exc:
|
|
1123
|
+
if "Received :status = '413'" in str(exc):
|
|
1130
1124
|
raise InvalidError(f"Function {info.function_name} is too large to deploy.")
|
|
1131
1125
|
raise
|
|
1132
1126
|
function_creation_status.set_response(response)
|
|
@@ -5,10 +5,10 @@ import grpclib.client
|
|
|
5
5
|
from google.protobuf.message import Message
|
|
6
6
|
from grpclib import GRPCError, Status
|
|
7
7
|
|
|
8
|
+
from . import exception
|
|
8
9
|
from ._traceback import suppress_tb_frames
|
|
9
10
|
from ._utils.grpc_utils import Retry, _retry_transient_errors
|
|
10
11
|
from .config import config, logger
|
|
11
|
-
from .exception import InvalidError, NotFoundError
|
|
12
12
|
|
|
13
13
|
if TYPE_CHECKING:
|
|
14
14
|
from .client import _Client
|
|
@@ -20,6 +20,29 @@ RequestType = TypeVar("RequestType", bound=Message)
|
|
|
20
20
|
ResponseType = TypeVar("ResponseType", bound=Message)
|
|
21
21
|
|
|
22
22
|
|
|
23
|
+
class WrappedGRPCError(exception.Error, exception._GRPCErrorWrapper): ...
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
_STATUS_TO_EXCEPTION: dict[Status, type[exception._GRPCErrorWrapper]] = {
|
|
27
|
+
Status.CANCELLED: exception.ServiceError,
|
|
28
|
+
Status.UNKNOWN: exception.ServiceError,
|
|
29
|
+
Status.INVALID_ARGUMENT: exception.InvalidError,
|
|
30
|
+
Status.DEADLINE_EXCEEDED: exception.ServiceError,
|
|
31
|
+
Status.NOT_FOUND: exception.NotFoundError,
|
|
32
|
+
Status.ALREADY_EXISTS: exception.AlreadyExistsError,
|
|
33
|
+
Status.PERMISSION_DENIED: exception.PermissionDeniedError,
|
|
34
|
+
Status.RESOURCE_EXHAUSTED: exception.ResourceExhaustedError,
|
|
35
|
+
Status.FAILED_PRECONDITION: exception.ConflictError,
|
|
36
|
+
Status.ABORTED: exception.ConflictError,
|
|
37
|
+
Status.OUT_OF_RANGE: exception.InvalidError,
|
|
38
|
+
Status.UNIMPLEMENTED: exception.UnimplementedError,
|
|
39
|
+
Status.INTERNAL: exception.InternalError,
|
|
40
|
+
Status.UNAVAILABLE: exception.ServiceError,
|
|
41
|
+
Status.DATA_LOSS: exception.DataLossError,
|
|
42
|
+
Status.UNAUTHENTICATED: exception.AuthError,
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
|
|
23
46
|
class grpc_error_converter:
|
|
24
47
|
def __enter__(self):
|
|
25
48
|
pass
|
|
@@ -29,20 +52,14 @@ class grpc_error_converter:
|
|
|
29
52
|
use_full_traceback = config.get("traceback")
|
|
30
53
|
with suppress_tb_frames(1):
|
|
31
54
|
if isinstance(exc, GRPCError):
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
tb = exc.__traceback__
|
|
41
|
-
while tb.tb_next:
|
|
42
|
-
tb = tb.tb_next
|
|
43
|
-
exc.with_traceback(tb)
|
|
44
|
-
raise exc from None # from None to skip the grpc-internal cause
|
|
45
|
-
raise exc
|
|
55
|
+
modal_exc = _STATUS_TO_EXCEPTION[exc.status](exc.message)
|
|
56
|
+
modal_exc._grpc_message = exc.message
|
|
57
|
+
modal_exc._grpc_status = exc.status
|
|
58
|
+
modal_exc._grpc_details = exc.details
|
|
59
|
+
if use_full_traceback:
|
|
60
|
+
raise modal_exc
|
|
61
|
+
else:
|
|
62
|
+
raise modal_exc from None # from None to skip the grpc-internal cause
|
|
46
63
|
|
|
47
64
|
return False
|
|
48
65
|
|
|
@@ -100,17 +117,20 @@ class UnaryUnaryWrapper(Generic[RequestType, ResponseType]):
|
|
|
100
117
|
) -> ResponseType:
|
|
101
118
|
with suppress_tb_frames(1):
|
|
102
119
|
if timeout is not None and retry is not None:
|
|
103
|
-
raise InvalidError("Retry must be None when timeout is set")
|
|
120
|
+
raise exception.InvalidError("Retry must be None when timeout is set")
|
|
104
121
|
|
|
105
122
|
if retry is None:
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
123
|
+
with grpc_error_converter():
|
|
124
|
+
return await self.direct(req, timeout=timeout, metadata=metadata)
|
|
125
|
+
|
|
126
|
+
# TODO do we need suppress_error_frames(1) here too?
|
|
127
|
+
with grpc_error_converter():
|
|
128
|
+
return await _retry_transient_errors(
|
|
129
|
+
self, # type: ignore
|
|
130
|
+
req,
|
|
131
|
+
retry=retry,
|
|
132
|
+
metadata=metadata,
|
|
133
|
+
)
|
|
114
134
|
|
|
115
135
|
async def direct(
|
|
116
136
|
self,
|
|
@@ -135,8 +155,7 @@ class UnaryUnaryWrapper(Generic[RequestType, ResponseType]):
|
|
|
135
155
|
#
|
|
136
156
|
# [1]: https://github.com/vmagamedov/grpclib/blob/62f968a4c84e3f64e6966097574ff0a59969ea9b/grpclib/client.py#L844
|
|
137
157
|
self.wrapped_method.channel = await self.client._get_channel(self.server_url)
|
|
138
|
-
|
|
139
|
-
return await self.client._call_unary(self.wrapped_method, req, timeout=timeout, metadata=metadata)
|
|
158
|
+
return await self.client._call_unary(self.wrapped_method, req, timeout=timeout, metadata=metadata)
|
|
140
159
|
|
|
141
160
|
|
|
142
161
|
class UnaryStreamWrapper(Generic[RequestType, ResponseType]):
|
|
@@ -167,5 +186,6 @@ class UnaryStreamWrapper(Generic[RequestType, ResponseType]):
|
|
|
167
186
|
logger.debug(f"refreshing client after snapshot for {self.name.rsplit('/', 1)[1]}")
|
|
168
187
|
self.client = await _Client.from_env()
|
|
169
188
|
self.wrapped_method.channel = await self.client._get_channel(self.server_url)
|
|
170
|
-
|
|
171
|
-
|
|
189
|
+
with grpc_error_converter():
|
|
190
|
+
async for response in self.client._call_stream(self.wrapped_method, request, metadata=metadata):
|
|
191
|
+
yield response
|
|
@@ -12,7 +12,7 @@ from collections.abc import Generator
|
|
|
12
12
|
from datetime import timedelta
|
|
13
13
|
from typing import Callable, ClassVar
|
|
14
14
|
|
|
15
|
-
from grpclib.exceptions import
|
|
15
|
+
from grpclib.exceptions import StreamTerminatedError
|
|
16
16
|
from rich.console import Console, Group, RenderableType
|
|
17
17
|
from rich.live import Live
|
|
18
18
|
from rich.panel import Panel
|
|
@@ -34,10 +34,11 @@ from rich.text import Text
|
|
|
34
34
|
from modal._utils.time_utils import timestamp_to_localized_str
|
|
35
35
|
from modal_proto import api_pb2
|
|
36
36
|
|
|
37
|
-
from ._utils.grpc_utils import
|
|
37
|
+
from ._utils.grpc_utils import Retry
|
|
38
38
|
from ._utils.shell_utils import stream_from_stdin, write_to_fd
|
|
39
39
|
from .client import _Client
|
|
40
40
|
from .config import logger
|
|
41
|
+
from .exception import InternalError, ServiceError
|
|
41
42
|
|
|
42
43
|
if platform.system() == "Windows":
|
|
43
44
|
default_spinner = "line"
|
|
@@ -556,7 +557,7 @@ async def get_app_logs_loop(
|
|
|
556
557
|
async def stop_pty_shell():
|
|
557
558
|
nonlocal pty_shell_finish_event, pty_shell_input_task
|
|
558
559
|
if pty_shell_finish_event:
|
|
559
|
-
print("\r", end="") # move cursor to beginning of line
|
|
560
|
+
print("\r", end="") # move cursor to beginning of line # noqa: T201
|
|
560
561
|
pty_shell_finish_event.set()
|
|
561
562
|
pty_shell_finish_event = None
|
|
562
563
|
|
|
@@ -623,7 +624,7 @@ async def get_app_logs_loop(
|
|
|
623
624
|
# This corresponds to the `modal run -i` use case where a breakpoint
|
|
624
625
|
# triggers and the task drops into an interactive PTY mode
|
|
625
626
|
if pty_shell_finish_event:
|
|
626
|
-
print("ERROR: concurrent PTY shells are not supported.")
|
|
627
|
+
print("ERROR: concurrent PTY shells are not supported.") # noqa: T201
|
|
627
628
|
else:
|
|
628
629
|
pty_shell_stdout = output_mgr._stdout
|
|
629
630
|
pty_shell_finish_event = asyncio.Event()
|
|
@@ -644,13 +645,11 @@ async def get_app_logs_loop(
|
|
|
644
645
|
while True:
|
|
645
646
|
try:
|
|
646
647
|
await _get_logs()
|
|
647
|
-
except (
|
|
648
|
-
if isinstance(exc,
|
|
649
|
-
if
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
logger.debug("Log fetching timed out. Retrying ...")
|
|
653
|
-
continue
|
|
648
|
+
except (ServiceError, InternalError, StreamTerminatedError, socket.gaierror, AttributeError) as exc:
|
|
649
|
+
if isinstance(exc, (ServiceError, InternalError)):
|
|
650
|
+
# Try again if we had a temporary connection drop, for example if computer went to sleep.
|
|
651
|
+
logger.debug("Log fetching timed out. Retrying ...")
|
|
652
|
+
continue
|
|
654
653
|
elif isinstance(exc, StreamTerminatedError):
|
|
655
654
|
logger.debug("Stream closed. Retrying ...")
|
|
656
655
|
continue
|
|
@@ -46,6 +46,7 @@ class _PartialFunctionFlags(enum.IntFlag):
|
|
|
46
46
|
BATCHED = 64
|
|
47
47
|
CONCURRENT = 128
|
|
48
48
|
CLUSTERED = 256 # Experimental: Clustered functions
|
|
49
|
+
HTTP_WEB_INTERFACE = 512 # Experimental: HTTP server
|
|
49
50
|
|
|
50
51
|
@staticmethod
|
|
51
52
|
def all() -> int:
|
|
@@ -76,6 +77,7 @@ class _PartialFunctionParams:
|
|
|
76
77
|
target_concurrent_inputs: Optional[int] = None
|
|
77
78
|
build_timeout: Optional[int] = None
|
|
78
79
|
rdma: Optional[bool] = None
|
|
80
|
+
http_config: Optional[api_pb2.HTTPConfig] = None
|
|
79
81
|
|
|
80
82
|
def update(self, other: "_PartialFunctionParams") -> None:
|
|
81
83
|
"""Update self with params set in other."""
|
|
@@ -845,8 +845,9 @@ class _ContainerIOManager:
|
|
|
845
845
|
yield inputs
|
|
846
846
|
yielded = True
|
|
847
847
|
|
|
848
|
-
#
|
|
849
|
-
|
|
848
|
+
# TODO(michael): Remove use of max_inputs after worker rollover
|
|
849
|
+
single_use_container = self.function_def.single_use_containers or self.function_def.max_inputs == 1
|
|
850
|
+
if final_input_received or single_use_container:
|
|
850
851
|
return
|
|
851
852
|
finally:
|
|
852
853
|
if not yielded:
|
|
@@ -991,12 +992,10 @@ class _ContainerIOManager:
|
|
|
991
992
|
# Busy-wait for restore. `/__modal/restore-state.json` is created
|
|
992
993
|
# by the worker process with updates to the container config.
|
|
993
994
|
restored_path = Path(config.get("restore_state_path"))
|
|
994
|
-
|
|
995
|
+
logger.debug("Waiting for restore")
|
|
995
996
|
while not restored_path.exists():
|
|
996
|
-
logger.debug(f"Waiting for restore (elapsed={time.perf_counter() - start:.3f}s)")
|
|
997
997
|
await asyncio.sleep(0.01)
|
|
998
998
|
continue
|
|
999
|
-
|
|
1000
999
|
logger.debug("Container: restored")
|
|
1001
1000
|
|
|
1002
1001
|
# Look for state file and create new client with updated credentials.
|
|
@@ -1007,7 +1006,7 @@ class _ContainerIOManager:
|
|
|
1007
1006
|
# Start a debugger if the worker tells us to
|
|
1008
1007
|
if int(restored_state.get("snapshot_debug", 0)):
|
|
1009
1008
|
logger.debug("Entering snapshot debugger")
|
|
1010
|
-
breakpoint()
|
|
1009
|
+
breakpoint() # noqa: T100
|
|
1011
1010
|
|
|
1012
1011
|
# Local ContainerIOManager state.
|
|
1013
1012
|
for key in ["task_id", "function_id"]:
|
|
@@ -18,11 +18,14 @@ from modal.config import config, logger
|
|
|
18
18
|
|
|
19
19
|
CUDA_CHECKPOINT_PATH: str = config.get("cuda_checkpoint_path")
|
|
20
20
|
|
|
21
|
-
# Maximum total duration for an entire toggle operation.
|
|
22
|
-
CUDA_CHECKPOINT_TOGGLE_TIMEOUT: float = 5 * 60.0
|
|
23
|
-
|
|
24
21
|
# Maximum total duration for each individual `cuda-checkpoint` invocation.
|
|
25
|
-
CUDA_CHECKPOINT_TIMEOUT: float =
|
|
22
|
+
CUDA_CHECKPOINT_TIMEOUT: float = 3 * 60.0
|
|
23
|
+
|
|
24
|
+
# Number of retries for each individual `cuda-checkpoint --toggle` invocation.
|
|
25
|
+
CUDA_CHECKPOINT_TOGGLE_NUM_RETRIES: int = 3
|
|
26
|
+
|
|
27
|
+
# Maximum total duration for an entire toggle operation.
|
|
28
|
+
CUDA_CHECKPOINT_TOGGLE_TIMEOUT: float = CUDA_CHECKPOINT_TOGGLE_NUM_RETRIES * CUDA_CHECKPOINT_TIMEOUT
|
|
26
29
|
|
|
27
30
|
|
|
28
31
|
class CudaCheckpointState(Enum):
|
|
@@ -58,7 +61,7 @@ class CudaCheckpointProcess:
|
|
|
58
61
|
|
|
59
62
|
start_time = time.monotonic()
|
|
60
63
|
retry_count = 0
|
|
61
|
-
max_retries =
|
|
64
|
+
max_retries = CUDA_CHECKPOINT_TOGGLE_NUM_RETRIES
|
|
62
65
|
|
|
63
66
|
attempts = 0
|
|
64
67
|
while self._should_continue_toggle(
|
|
@@ -201,8 +204,7 @@ class CudaCheckpointSession:
|
|
|
201
204
|
[CUDA_CHECKPOINT_PATH, "--get-state", "--pid", str(pid)],
|
|
202
205
|
capture_output=True,
|
|
203
206
|
text=True,
|
|
204
|
-
|
|
205
|
-
timeout=5,
|
|
207
|
+
timeout=CUDA_CHECKPOINT_TIMEOUT,
|
|
206
208
|
)
|
|
207
209
|
|
|
208
210
|
# If the command succeeds (return code 0), this PID has a CUDA session
|