modAL 1.2.7.dev10__tar.gz → 1.2.7.dev12__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.2.7.dev10 → modal-1.2.7.dev12}/PKG-INFO +5 -5
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/README.md +1 -1
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/__init__.py +2 -2
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_grpc_client.py +1 -1
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_output.py +8 -9
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_runtime/container_io_manager.pyi +42 -44
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_serialization.py +2 -1
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_utils/function_utils.py +8 -9
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_utils/rand_pb_testing.py +8 -1
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_vendor/cloudpickle.py +144 -48
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/app.pyi +11 -11
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/builder/2025.06.txt +2 -1
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/builder/PREVIEW.txt +2 -1
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/builder/base-images.json +4 -2
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/cli/run.py +14 -4
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/client.pyi +86 -48
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/cls.py +1 -1
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/cls.pyi +6 -8
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/container_process.pyi +6 -8
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/dict.py +14 -7
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/dict.pyi +84 -57
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/exception.py +5 -1
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/experimental/flash.pyi +28 -30
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/file_io.py +10 -13
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/file_io.pyi +105 -62
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/functions.pyi +54 -58
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/image.py +13 -8
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/image.pyi +5 -5
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/io_streams.py +10 -13
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/io_streams.pyi +4 -6
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/mount.py +3 -3
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/mount.pyi +8 -10
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/network_file_system.pyi +60 -37
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/object.pyi +91 -26
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/parallel_map.pyi +6 -8
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/partial_function.pyi +0 -1
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/queue.py +13 -6
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/queue.pyi +76 -50
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/sandbox.py +3 -2
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/sandbox.pyi +52 -54
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/secret.py +2 -1
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/secret.pyi +7 -9
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/snapshot.pyi +1 -1
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/token_flow.pyi +4 -6
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/volume.py +2 -1
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/volume.pyi +87 -62
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal.egg-info/PKG-INFO +5 -5
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal.egg-info/requires.txt +2 -2
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal_version/__init__.py +1 -1
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/pyproject.toml +4 -3
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/LICENSE +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/__main__.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_billing.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_clustered_functions.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_clustered_functions.pyi +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_container_entrypoint.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_functions.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_ipython.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_load_context.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_location.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_object.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_partial_function.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_pty.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_resolver.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_resources.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_runtime/__init__.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_runtime/asgi.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_runtime/container_io_manager.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_runtime/execution_context.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_runtime/execution_context.pyi +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_runtime/gpu_memory_snapshot.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_runtime/telemetry.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_runtime/user_code_event_loop.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_runtime/user_code_imports.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_traceback.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_tunnel.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_tunnel.pyi +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_type_manager.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_utils/__init__.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_utils/app_utils.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_utils/async_utils.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_utils/auth_token_manager.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_utils/blob_utils.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_utils/bytes_io_segment_payload.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_utils/deprecation.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_utils/docker_utils.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_utils/git_utils.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_utils/grpc_testing.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_utils/grpc_utils.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_utils/hash_utils.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_utils/http_utils.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_utils/jwt_utils.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_utils/logger.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_utils/mount_utils.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_utils/name_utils.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_utils/package_utils.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_utils/pattern_utils.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_utils/shell_utils.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_utils/task_command_router_client.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_utils/time_utils.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_vendor/__init__.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_vendor/a2wsgi_wsgi.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_vendor/tblib.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/_watcher.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/app.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/billing.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/builder/2023.12.312.txt +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/builder/2023.12.txt +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/builder/2024.04.txt +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/builder/2024.10.txt +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/builder/README.md +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/call_graph.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/cli/__init__.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/cli/_download.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/cli/_traceback.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/cli/app.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/cli/cluster.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/cli/config.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/cli/container.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/cli/dict.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/cli/entry_point.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/cli/environment.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/cli/import_refs.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/cli/launch.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/cli/network_file_system.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/cli/profile.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/cli/programs/__init__.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/cli/programs/run_jupyter.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/cli/programs/vscode.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/cli/queues.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/cli/secret.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/cli/shell.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/cli/token.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/cli/utils.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/cli/volume.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/client.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/cloud_bucket_mount.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/cloud_bucket_mount.pyi +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/config.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/container_process.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/environments.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/environments.pyi +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/experimental/__init__.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/experimental/flash.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/experimental/ipython.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/file_pattern_matcher.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/functions.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/gpu.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/network_file_system.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/object.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/output.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/parallel_map.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/partial_function.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/proxy.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/proxy.pyi +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/py.typed +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/retries.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/runner.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/runner.pyi +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/running_app.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/schedule.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/scheduler_placement.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/serving.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/serving.pyi +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/snapshot.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/stream_type.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal/token_flow.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal.egg-info/SOURCES.txt +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal.egg-info/dependency_links.txt +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal.egg-info/entry_points.txt +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal.egg-info/top_level.txt +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal_docs/__init__.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal_docs/gen_cli_docs.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal_docs/gen_reference_docs.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal_docs/mdmd/__init__.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal_docs/mdmd/mdmd.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal_docs/mdmd/signatures.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal_proto/__init__.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal_proto/api.proto +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal_proto/api_grpc.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal_proto/api_pb2.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal_proto/api_pb2.pyi +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal_proto/api_pb2_grpc.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal_proto/api_pb2_grpc.pyi +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal_proto/modal_api_grpc.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal_proto/py.typed +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal_proto/task_command_router.proto +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal_proto/task_command_router_grpc.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal_proto/task_command_router_pb2.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal_proto/task_command_router_pb2.pyi +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal_proto/task_command_router_pb2_grpc.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal_proto/task_command_router_pb2_grpc.pyi +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/modal_version/__main__.py +0 -0
- {modal-1.2.7.dev10 → modal-1.2.7.dev12}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: modal
|
|
3
|
-
Version: 1.2.7.
|
|
3
|
+
Version: 1.2.7.dev12
|
|
4
4
|
Summary: Python client library for Modal
|
|
5
5
|
Author-email: Modal Labs <support@modal.com>
|
|
6
6
|
License: Apache-2.0
|
|
@@ -13,17 +13,17 @@ 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.
|
|
16
|
+
Requires-Python: <3.15,>=3.10
|
|
17
17
|
Description-Content-Type: text/markdown
|
|
18
18
|
License-File: LICENSE
|
|
19
19
|
Requires-Dist: aiohttp
|
|
20
20
|
Requires-Dist: cbor2
|
|
21
21
|
Requires-Dist: certifi
|
|
22
22
|
Requires-Dist: click~=8.1
|
|
23
|
-
Requires-Dist: grpclib<0.4.
|
|
23
|
+
Requires-Dist: grpclib<0.4.10,>=0.4.7
|
|
24
24
|
Requires-Dist: protobuf!=4.24.0,<7.0,>=3.19
|
|
25
25
|
Requires-Dist: rich>=12.0.0
|
|
26
|
-
Requires-Dist: synchronicity~=0.
|
|
26
|
+
Requires-Dist: synchronicity~=0.11.1
|
|
27
27
|
Requires-Dist: toml
|
|
28
28
|
Requires-Dist: typer>=0.9
|
|
29
29
|
Requires-Dist: types-certifi
|
|
@@ -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.10 – 3.
|
|
54
|
+
**This library requires Python 3.10 – 3.14.**
|
|
55
55
|
|
|
56
56
|
Install the package with `uv` or `pip`:
|
|
57
57
|
|
|
@@ -3,8 +3,8 @@ import sys
|
|
|
3
3
|
|
|
4
4
|
if sys.version_info[:2] < (3, 10):
|
|
5
5
|
raise RuntimeError("This version of Modal requires at least Python 3.10")
|
|
6
|
-
if sys.version_info[:2] >= (3,
|
|
7
|
-
raise RuntimeError("This version of Modal does not support Python 3.
|
|
6
|
+
if sys.version_info[:2] >= (3, 15):
|
|
7
|
+
raise RuntimeError("This version of Modal does not support Python 3.15+")
|
|
8
8
|
|
|
9
9
|
from modal_version import __version__
|
|
10
10
|
|
|
@@ -38,7 +38,7 @@ _STATUS_TO_EXCEPTION: dict[Status, type[exception._GRPCErrorWrapper]] = {
|
|
|
38
38
|
Status.UNIMPLEMENTED: exception.UnimplementedError,
|
|
39
39
|
Status.INTERNAL: exception.InternalError,
|
|
40
40
|
Status.UNAVAILABLE: exception.ServiceError,
|
|
41
|
-
Status.DATA_LOSS: exception.
|
|
41
|
+
Status.DATA_LOSS: exception.DataLossError,
|
|
42
42
|
Status.UNAUTHENTICATED: exception.AuthError,
|
|
43
43
|
}
|
|
44
44
|
|
|
@@ -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"
|
|
@@ -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
|
|
@@ -252,8 +252,6 @@ class _ContainerIOManager:
|
|
|
252
252
|
@classmethod
|
|
253
253
|
def stop_fetching_inputs(cls): ...
|
|
254
254
|
|
|
255
|
-
SUPERSELF = typing.TypeVar("SUPERSELF", covariant=True)
|
|
256
|
-
|
|
257
255
|
class ContainerIOManager:
|
|
258
256
|
"""Synchronizes all RPC calls and network operations for a running container.
|
|
259
257
|
|
|
@@ -298,47 +296,47 @@ class ContainerIOManager:
|
|
|
298
296
|
"""Only used for tests."""
|
|
299
297
|
...
|
|
300
298
|
|
|
301
|
-
class __hello_spec(typing_extensions.Protocol
|
|
299
|
+
class __hello_spec(typing_extensions.Protocol):
|
|
302
300
|
def __call__(self, /): ...
|
|
303
301
|
async def aio(self, /): ...
|
|
304
302
|
|
|
305
|
-
hello: __hello_spec
|
|
303
|
+
hello: __hello_spec
|
|
306
304
|
|
|
307
|
-
class ___run_heartbeat_loop_spec(typing_extensions.Protocol
|
|
305
|
+
class ___run_heartbeat_loop_spec(typing_extensions.Protocol):
|
|
308
306
|
def __call__(self, /): ...
|
|
309
307
|
async def aio(self, /): ...
|
|
310
308
|
|
|
311
|
-
_run_heartbeat_loop: ___run_heartbeat_loop_spec
|
|
309
|
+
_run_heartbeat_loop: ___run_heartbeat_loop_spec
|
|
312
310
|
|
|
313
|
-
class ___heartbeat_handle_cancellations_spec(typing_extensions.Protocol
|
|
311
|
+
class ___heartbeat_handle_cancellations_spec(typing_extensions.Protocol):
|
|
314
312
|
def __call__(self, /) -> bool: ...
|
|
315
313
|
async def aio(self, /) -> bool: ...
|
|
316
314
|
|
|
317
|
-
_heartbeat_handle_cancellations: ___heartbeat_handle_cancellations_spec
|
|
315
|
+
_heartbeat_handle_cancellations: ___heartbeat_handle_cancellations_spec
|
|
318
316
|
|
|
319
|
-
class __heartbeats_spec(typing_extensions.Protocol
|
|
317
|
+
class __heartbeats_spec(typing_extensions.Protocol):
|
|
320
318
|
def __call__(
|
|
321
319
|
self, /, wait_for_mem_snap: bool
|
|
322
320
|
) -> synchronicity.combined_types.AsyncAndBlockingContextManager[None]: ...
|
|
323
321
|
def aio(self, /, wait_for_mem_snap: bool) -> typing.AsyncContextManager[None]: ...
|
|
324
322
|
|
|
325
|
-
heartbeats: __heartbeats_spec
|
|
323
|
+
heartbeats: __heartbeats_spec
|
|
326
324
|
|
|
327
325
|
def stop_heartbeat(self): ...
|
|
328
326
|
|
|
329
|
-
class __dynamic_concurrency_manager_spec(typing_extensions.Protocol
|
|
327
|
+
class __dynamic_concurrency_manager_spec(typing_extensions.Protocol):
|
|
330
328
|
def __call__(self, /) -> synchronicity.combined_types.AsyncAndBlockingContextManager[None]: ...
|
|
331
329
|
def aio(self, /) -> typing.AsyncContextManager[None]: ...
|
|
332
330
|
|
|
333
|
-
dynamic_concurrency_manager: __dynamic_concurrency_manager_spec
|
|
331
|
+
dynamic_concurrency_manager: __dynamic_concurrency_manager_spec
|
|
334
332
|
|
|
335
|
-
class ___dynamic_concurrency_loop_spec(typing_extensions.Protocol
|
|
333
|
+
class ___dynamic_concurrency_loop_spec(typing_extensions.Protocol):
|
|
336
334
|
def __call__(self, /): ...
|
|
337
335
|
async def aio(self, /): ...
|
|
338
336
|
|
|
339
|
-
_dynamic_concurrency_loop: ___dynamic_concurrency_loop_spec
|
|
337
|
+
_dynamic_concurrency_loop: ___dynamic_concurrency_loop_spec
|
|
340
338
|
|
|
341
|
-
class __get_data_in_spec(typing_extensions.Protocol
|
|
339
|
+
class __get_data_in_spec(typing_extensions.Protocol):
|
|
342
340
|
def __call__(
|
|
343
341
|
self, /, function_call_id: str, attempt_token: typing.Optional[str]
|
|
344
342
|
) -> typing.Iterator[typing.Any]:
|
|
@@ -351,9 +349,9 @@ class ContainerIOManager:
|
|
|
351
349
|
"""Read from the `data_in` stream of a function call."""
|
|
352
350
|
...
|
|
353
351
|
|
|
354
|
-
get_data_in: __get_data_in_spec
|
|
352
|
+
get_data_in: __get_data_in_spec
|
|
355
353
|
|
|
356
|
-
class __put_data_out_spec(typing_extensions.Protocol
|
|
354
|
+
class __put_data_out_spec(typing_extensions.Protocol):
|
|
357
355
|
def __call__(
|
|
358
356
|
self,
|
|
359
357
|
/,
|
|
@@ -388,9 +386,9 @@ class ContainerIOManager:
|
|
|
388
386
|
"""
|
|
389
387
|
...
|
|
390
388
|
|
|
391
|
-
put_data_out: __put_data_out_spec
|
|
389
|
+
put_data_out: __put_data_out_spec
|
|
392
390
|
|
|
393
|
-
class __generator_output_sender_spec(typing_extensions.Protocol
|
|
391
|
+
class __generator_output_sender_spec(typing_extensions.Protocol):
|
|
394
392
|
def __call__(
|
|
395
393
|
self, /, function_call_id: str, attempt_token: str, data_format: int, message_rx: asyncio.queues.Queue
|
|
396
394
|
) -> synchronicity.combined_types.AsyncAndBlockingContextManager[None]:
|
|
@@ -403,9 +401,9 @@ class ContainerIOManager:
|
|
|
403
401
|
"""Runs background task that feeds generator outputs into a function call's `data_out` stream."""
|
|
404
402
|
...
|
|
405
403
|
|
|
406
|
-
generator_output_sender: __generator_output_sender_spec
|
|
404
|
+
generator_output_sender: __generator_output_sender_spec
|
|
407
405
|
|
|
408
|
-
class ___queue_create_spec(typing_extensions.Protocol
|
|
406
|
+
class ___queue_create_spec(typing_extensions.Protocol):
|
|
409
407
|
def __call__(self, /, size: int) -> asyncio.queues.Queue:
|
|
410
408
|
"""Create a queue, on the synchronicity event loop (needed on Python 3.8 and 3.9)."""
|
|
411
409
|
...
|
|
@@ -414,9 +412,9 @@ class ContainerIOManager:
|
|
|
414
412
|
"""Create a queue, on the synchronicity event loop (needed on Python 3.8 and 3.9)."""
|
|
415
413
|
...
|
|
416
414
|
|
|
417
|
-
_queue_create: ___queue_create_spec
|
|
415
|
+
_queue_create: ___queue_create_spec
|
|
418
416
|
|
|
419
|
-
class ___queue_put_spec(typing_extensions.Protocol
|
|
417
|
+
class ___queue_put_spec(typing_extensions.Protocol):
|
|
420
418
|
def __call__(self, /, queue: asyncio.queues.Queue, value: typing.Any) -> None:
|
|
421
419
|
"""Put a value onto a queue, using the synchronicity event loop."""
|
|
422
420
|
...
|
|
@@ -425,12 +423,12 @@ class ContainerIOManager:
|
|
|
425
423
|
"""Put a value onto a queue, using the synchronicity event loop."""
|
|
426
424
|
...
|
|
427
425
|
|
|
428
|
-
_queue_put: ___queue_put_spec
|
|
426
|
+
_queue_put: ___queue_put_spec
|
|
429
427
|
|
|
430
428
|
def get_average_call_time(self) -> float: ...
|
|
431
429
|
def get_max_inputs_to_fetch(self): ...
|
|
432
430
|
|
|
433
|
-
class ___generate_inputs_spec(typing_extensions.Protocol
|
|
431
|
+
class ___generate_inputs_spec(typing_extensions.Protocol):
|
|
434
432
|
def __call__(
|
|
435
433
|
self, /, batch_max_size: int, batch_wait_ms: int
|
|
436
434
|
) -> typing.Iterator[list[tuple[str, int, str, str, modal_proto.api_pb2.FunctionInput]]]: ...
|
|
@@ -438,9 +436,9 @@ class ContainerIOManager:
|
|
|
438
436
|
self, /, batch_max_size: int, batch_wait_ms: int
|
|
439
437
|
) -> collections.abc.AsyncIterator[list[tuple[str, int, str, str, modal_proto.api_pb2.FunctionInput]]]: ...
|
|
440
438
|
|
|
441
|
-
_generate_inputs: ___generate_inputs_spec
|
|
439
|
+
_generate_inputs: ___generate_inputs_spec
|
|
442
440
|
|
|
443
|
-
class __run_inputs_outputs_spec(typing_extensions.Protocol
|
|
441
|
+
class __run_inputs_outputs_spec(typing_extensions.Protocol):
|
|
444
442
|
def __call__(
|
|
445
443
|
self,
|
|
446
444
|
/,
|
|
@@ -456,9 +454,9 @@ class ContainerIOManager:
|
|
|
456
454
|
batch_wait_ms: int = 0,
|
|
457
455
|
) -> collections.abc.AsyncIterator[IOContext]: ...
|
|
458
456
|
|
|
459
|
-
run_inputs_outputs: __run_inputs_outputs_spec
|
|
457
|
+
run_inputs_outputs: __run_inputs_outputs_spec
|
|
460
458
|
|
|
461
|
-
class ___send_outputs_spec(typing_extensions.Protocol
|
|
459
|
+
class ___send_outputs_spec(typing_extensions.Protocol):
|
|
462
460
|
def __call__(self, /, started_at: float, outputs: list[modal_proto.api_pb2.FunctionPutOutputsItem]) -> None:
|
|
463
461
|
"""Send pre-built output items with retry and chunking."""
|
|
464
462
|
...
|
|
@@ -467,9 +465,9 @@ class ContainerIOManager:
|
|
|
467
465
|
"""Send pre-built output items with retry and chunking."""
|
|
468
466
|
...
|
|
469
467
|
|
|
470
|
-
_send_outputs: ___send_outputs_spec
|
|
468
|
+
_send_outputs: ___send_outputs_spec
|
|
471
469
|
|
|
472
|
-
class __handle_user_exception_spec(typing_extensions.Protocol
|
|
470
|
+
class __handle_user_exception_spec(typing_extensions.Protocol):
|
|
473
471
|
def __call__(self, /) -> synchronicity.combined_types.AsyncAndBlockingContextManager[None]:
|
|
474
472
|
"""Sets the task as failed in a way where it's not retried.
|
|
475
473
|
|
|
@@ -486,9 +484,9 @@ class ContainerIOManager:
|
|
|
486
484
|
"""
|
|
487
485
|
...
|
|
488
486
|
|
|
489
|
-
handle_user_exception: __handle_user_exception_spec
|
|
487
|
+
handle_user_exception: __handle_user_exception_spec
|
|
490
488
|
|
|
491
|
-
class __handle_input_exception_spec(typing_extensions.Protocol
|
|
489
|
+
class __handle_input_exception_spec(typing_extensions.Protocol):
|
|
492
490
|
def __call__(
|
|
493
491
|
self, /, io_context: IOContext, started_at: float
|
|
494
492
|
) -> synchronicity.combined_types.AsyncAndBlockingContextManager[None]:
|
|
@@ -499,23 +497,23 @@ class ContainerIOManager:
|
|
|
499
497
|
"""Handle an exception while processing a function input."""
|
|
500
498
|
...
|
|
501
499
|
|
|
502
|
-
handle_input_exception: __handle_input_exception_spec
|
|
500
|
+
handle_input_exception: __handle_input_exception_spec
|
|
503
501
|
|
|
504
502
|
def exit_context(self, started_at, input_ids: list[str]): ...
|
|
505
503
|
|
|
506
|
-
class __push_outputs_spec(typing_extensions.Protocol
|
|
504
|
+
class __push_outputs_spec(typing_extensions.Protocol):
|
|
507
505
|
def __call__(self, /, io_context: IOContext, started_at: float, output_data: list[typing.Any]) -> None: ...
|
|
508
506
|
async def aio(self, /, io_context: IOContext, started_at: float, output_data: list[typing.Any]) -> None: ...
|
|
509
507
|
|
|
510
|
-
push_outputs: __push_outputs_spec
|
|
508
|
+
push_outputs: __push_outputs_spec
|
|
511
509
|
|
|
512
|
-
class __memory_restore_spec(typing_extensions.Protocol
|
|
510
|
+
class __memory_restore_spec(typing_extensions.Protocol):
|
|
513
511
|
def __call__(self, /) -> None: ...
|
|
514
512
|
async def aio(self, /) -> None: ...
|
|
515
513
|
|
|
516
|
-
memory_restore: __memory_restore_spec
|
|
514
|
+
memory_restore: __memory_restore_spec
|
|
517
515
|
|
|
518
|
-
class __memory_snapshot_spec(typing_extensions.Protocol
|
|
516
|
+
class __memory_snapshot_spec(typing_extensions.Protocol):
|
|
519
517
|
def __call__(self, /) -> None:
|
|
520
518
|
"""Message server indicating that function is ready to be checkpointed."""
|
|
521
519
|
...
|
|
@@ -524,9 +522,9 @@ class ContainerIOManager:
|
|
|
524
522
|
"""Message server indicating that function is ready to be checkpointed."""
|
|
525
523
|
...
|
|
526
524
|
|
|
527
|
-
memory_snapshot: __memory_snapshot_spec
|
|
525
|
+
memory_snapshot: __memory_snapshot_spec
|
|
528
526
|
|
|
529
|
-
class __volume_commit_spec(typing_extensions.Protocol
|
|
527
|
+
class __volume_commit_spec(typing_extensions.Protocol):
|
|
530
528
|
def __call__(self, /, volume_ids: list[str]) -> None:
|
|
531
529
|
"""Perform volume commit for given `volume_ids`.
|
|
532
530
|
Only used on container exit to persist uncommitted changes on behalf of user.
|
|
@@ -539,13 +537,13 @@ class ContainerIOManager:
|
|
|
539
537
|
"""
|
|
540
538
|
...
|
|
541
539
|
|
|
542
|
-
volume_commit: __volume_commit_spec
|
|
540
|
+
volume_commit: __volume_commit_spec
|
|
543
541
|
|
|
544
|
-
class __interact_spec(typing_extensions.Protocol
|
|
542
|
+
class __interact_spec(typing_extensions.Protocol):
|
|
545
543
|
def __call__(self, /, from_breakpoint: bool = False): ...
|
|
546
544
|
async def aio(self, /, from_breakpoint: bool = False): ...
|
|
547
545
|
|
|
548
|
-
interact: __interact_spec
|
|
546
|
+
interact: __interact_spec
|
|
549
547
|
|
|
550
548
|
@property
|
|
551
549
|
def target_concurrency(self) -> int: ...
|
|
@@ -420,7 +420,8 @@ def check_valid_cls_constructor_arg(key, obj):
|
|
|
420
420
|
try:
|
|
421
421
|
ClsConstructorPickler(buf).dump(obj)
|
|
422
422
|
return True
|
|
423
|
-
except (AttributeError, ValueError):
|
|
423
|
+
except (AttributeError, ValueError, pickle.PicklingError):
|
|
424
|
+
# Python 3.14+ now raises an PicklingError for certain types of `dump` failures
|
|
424
425
|
raise ValueError(
|
|
425
426
|
f"Only pickle-able types are allowed in remote class constructors: argument {key} of type {type(obj)}."
|
|
426
427
|
)
|
|
@@ -8,7 +8,6 @@ from enum import Enum
|
|
|
8
8
|
from pathlib import Path, PurePosixPath
|
|
9
9
|
from typing import Any, Callable, Literal, Optional
|
|
10
10
|
|
|
11
|
-
from grpclib import GRPCError
|
|
12
11
|
from grpclib.exceptions import StreamTerminatedError
|
|
13
12
|
|
|
14
13
|
import modal_proto
|
|
@@ -29,9 +28,11 @@ from ..exception import (
|
|
|
29
28
|
DeserializationError,
|
|
30
29
|
ExecutionError,
|
|
31
30
|
FunctionTimeoutError,
|
|
31
|
+
InternalError,
|
|
32
32
|
InternalFailure,
|
|
33
33
|
InvalidError,
|
|
34
34
|
RemoteError,
|
|
35
|
+
ServiceError,
|
|
35
36
|
)
|
|
36
37
|
from ..mount import ROOT_DIR, _is_modal_path, _Mount
|
|
37
38
|
from .blob_utils import (
|
|
@@ -39,7 +40,6 @@ from .blob_utils import (
|
|
|
39
40
|
blob_download,
|
|
40
41
|
blob_upload_with_r2_failure_info,
|
|
41
42
|
)
|
|
42
|
-
from .grpc_utils import RETRYABLE_GRPC_STATUS_CODES
|
|
43
43
|
|
|
44
44
|
if typing.TYPE_CHECKING:
|
|
45
45
|
import modal._functions
|
|
@@ -437,15 +437,14 @@ async def _stream_function_call_data(
|
|
|
437
437
|
|
|
438
438
|
last_index = chunk.index
|
|
439
439
|
yield message
|
|
440
|
-
except (
|
|
440
|
+
except (ServiceError, InternalError, StreamTerminatedError) as exc:
|
|
441
441
|
if retries_remaining > 0:
|
|
442
442
|
retries_remaining -= 1
|
|
443
|
-
if isinstance(exc,
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
continue
|
|
443
|
+
if isinstance(exc, (ServiceError, InternalError)):
|
|
444
|
+
logger.debug(f"{variant} stream retrying with delay {delay_ms}ms due to {exc}")
|
|
445
|
+
await asyncio.sleep(delay_ms / 1000)
|
|
446
|
+
delay_ms = min(1000, delay_ms * 10)
|
|
447
|
+
continue
|
|
449
448
|
elif isinstance(exc, StreamTerminatedError):
|
|
450
449
|
continue
|
|
451
450
|
raise
|
|
@@ -45,7 +45,14 @@ def _fill(msg, desc: Descriptor, rand: Random) -> None:
|
|
|
45
45
|
if field.containing_oneof is not None and field.name not in oneof_fields:
|
|
46
46
|
continue
|
|
47
47
|
is_message = field.type == FieldDescriptor.TYPE_MESSAGE
|
|
48
|
-
|
|
48
|
+
|
|
49
|
+
# In the C implemenation of protobuf for Python 3.14, it raises a depreation
|
|
50
|
+
# warning when labels is accessed, but it does not clean up the exception state,
|
|
51
|
+
# causing an SystemError.
|
|
52
|
+
if hasattr(field, "is_repeated"):
|
|
53
|
+
is_repeated = field.is_repeated # type: ignore
|
|
54
|
+
else:
|
|
55
|
+
is_repeated = field.label == FieldDescriptor.LABEL_REPEATED
|
|
49
56
|
if is_message:
|
|
50
57
|
msg_field = getattr(msg, field.name)
|
|
51
58
|
if is_repeated:
|