modal 1.4.2.dev0__tar.gz → 1.4.2.dev2__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.dev0 → modal-1.4.2.dev2}/PKG-INFO +1 -1
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_utils/rand_pb_testing.py +3 -1
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_utils/task_command_router_client.py +69 -24
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/app.py +2 -2
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/app.pyi +4 -4
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cli/app.py +67 -1
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cli/import_refs.py +21 -2
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cli/run.py +3 -3
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cli/shell.py +1 -1
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/client.pyi +2 -2
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/config.py +2 -1
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/functions.pyi +6 -6
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/sandbox.py +7 -4
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal.egg-info/PKG-INFO +1 -1
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal_proto/api_grpc.py +48 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal_proto/api_pb2.py +1126 -1045
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal_proto/api_pb2.pyi +148 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal_proto/api_pb2_grpc.py +100 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal_proto/api_pb2_grpc.pyi +32 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal_proto/modal_api_grpc.py +3 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal_proto/task_command_router_grpc.py +16 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal_proto/task_command_router_pb2.py +19 -9
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal_proto/task_command_router_pb2.pyi +17 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal_proto/task_command_router_pb2_grpc.py +34 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal_proto/task_command_router_pb2_grpc.pyi +12 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal_version/__init__.py +1 -1
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/LICENSE +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/README.md +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/__init__.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/__main__.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_billing.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_clustered_functions.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_clustered_functions.pyi +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_container_entrypoint.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_functions.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_grpc_client.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_ipython.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_load_context.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_location.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_logs.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_object.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_output/__init__.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_output/manager.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_output/pty.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_output/rich.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_output/status.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_partial_function.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_resolver.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_resources.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_runtime/__init__.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_runtime/asgi.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_runtime/container_io_manager.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_runtime/container_io_manager.pyi +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_runtime/execution_context.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_runtime/execution_context.pyi +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_runtime/gpu_memory_snapshot.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_runtime/telemetry.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_runtime/user_code_event_loop.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_runtime/user_code_imports.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_serialization.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_server.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_traceback.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_tunnel.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_tunnel.pyi +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_type_manager.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_utils/__init__.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_utils/app_utils.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_utils/async_utils.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_utils/auth_token_manager.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_utils/blob_utils.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_utils/browser_utils.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_utils/bytes_io_segment_payload.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_utils/deprecation.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_utils/docker_utils.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_utils/function_utils.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_utils/git_utils.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_utils/grpc_testing.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_utils/grpc_utils.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_utils/hash_utils.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_utils/http_utils.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_utils/jwt_utils.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_utils/logger.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_utils/mount_utils.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_utils/name_utils.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_utils/package_utils.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_utils/pattern_utils.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_utils/sandbox_fs_utils.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_utils/shell_utils.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_utils/time_utils.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_vendor/__init__.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_vendor/a2wsgi_wsgi.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_vendor/cloudpickle.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_vendor/tblib.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_vendor/version.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_watcher.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/billing.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/builder/2023.12.312.txt +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/builder/2023.12.txt +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/builder/2024.04.txt +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/builder/2024.10.txt +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/builder/2025.06.txt +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/builder/PREVIEW.txt +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/builder/README.md +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/builder/base-images.json +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/call_graph.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cli/__init__.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cli/_download.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cli/_traceback.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cli/billing.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cli/changelog.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cli/cluster.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cli/config.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cli/container.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cli/dashboard.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cli/dict.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cli/entry_point.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cli/environment.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cli/launch.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cli/network_file_system.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cli/profile.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cli/programs/__init__.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cli/programs/run_jupyter.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cli/programs/vscode.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cli/queues.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cli/secret.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cli/selector.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cli/token.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cli/utils.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cli/volume.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/client.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cloud_bucket_mount.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cloud_bucket_mount.pyi +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cls.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cls.pyi +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/container_process.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/container_process.pyi +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/dict.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/dict.pyi +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/environments.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/environments.pyi +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/exception.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/experimental/__init__.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/experimental/flash.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/experimental/flash.pyi +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/experimental/ipython.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/file_io.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/file_io.pyi +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/file_pattern_matcher.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/functions.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/image.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/image.pyi +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/io_streams.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/io_streams.pyi +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/mount.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/mount.pyi +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/network_file_system.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/network_file_system.pyi +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/object.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/object.pyi +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/output.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/parallel_map.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/parallel_map.pyi +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/partial_function.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/partial_function.pyi +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/proxy.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/proxy.pyi +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/py.typed +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/queue.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/queue.pyi +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/retries.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/runner.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/runner.pyi +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/running_app.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/sandbox.pyi +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/sandbox_fs.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/sandbox_fs.pyi +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/schedule.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/scheduler_placement.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/secret.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/secret.pyi +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/server.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/server.pyi +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/serving.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/serving.pyi +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/snapshot.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/snapshot.pyi +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/stream_type.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/token_flow.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/token_flow.pyi +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/volume.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/volume.pyi +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal.egg-info/SOURCES.txt +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal.egg-info/dependency_links.txt +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal.egg-info/entry_points.txt +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal.egg-info/requires.txt +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal.egg-info/top_level.txt +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal_docs/__init__.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal_docs/gen_cli_docs.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal_docs/gen_cli_docs_main.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal_docs/gen_reference_docs.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal_docs/gen_reference_docs_main.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal_docs/mdmd/__init__.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal_docs/mdmd/mdmd.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal_docs/mdmd/signatures.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal_proto/__init__.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal_proto/py.typed +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal_version/__main__.py +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/pyproject.toml +0 -0
- {modal-1.4.2.dev0 → modal-1.4.2.dev2}/setup.cfg +0 -0
|
@@ -52,8 +52,9 @@ def _fill(msg, desc: Descriptor, rand: Random) -> None:
|
|
|
52
52
|
if hasattr(field, "is_repeated"):
|
|
53
53
|
is_repeated = field.is_repeated # type: ignore
|
|
54
54
|
else:
|
|
55
|
-
is_repeated = field.label == FieldDescriptor.LABEL_REPEATED
|
|
55
|
+
is_repeated = field.label == FieldDescriptor.LABEL_REPEATED # type: ignore[attr-defined]
|
|
56
56
|
if is_message:
|
|
57
|
+
assert field.message_type is not None
|
|
57
58
|
msg_field = getattr(msg, field.name)
|
|
58
59
|
if is_repeated:
|
|
59
60
|
num = rand.randint(0, 2)
|
|
@@ -64,6 +65,7 @@ def _fill(msg, desc: Descriptor, rand: Random) -> None:
|
|
|
64
65
|
_fill(msg_field, field.message_type, rand)
|
|
65
66
|
else:
|
|
66
67
|
if field.type == FieldDescriptor.TYPE_ENUM:
|
|
68
|
+
assert field.enum_type is not None
|
|
67
69
|
enum_values = [x.number for x in field.enum_type.values]
|
|
68
70
|
generator = lambda rand: rand.choice(enum_values) # noqa: E731
|
|
69
71
|
|
|
@@ -122,6 +122,15 @@ async def fetch_command_router_access(server_client, task_id: str) -> api_pb2.Ta
|
|
|
122
122
|
)
|
|
123
123
|
|
|
124
124
|
|
|
125
|
+
async def fetch_command_router_access_v2(
|
|
126
|
+
server_client, sandbox_id: str
|
|
127
|
+
) -> api_pb2.SandboxGetCommandRouterAccessResponse:
|
|
128
|
+
"""Fetch direct command router access info from Modal server for a V2 sandbox."""
|
|
129
|
+
return await server_client.stub.SandboxGetCommandRouterAccess(
|
|
130
|
+
api_pb2.SandboxGetCommandRouterAccessRequest(sandbox_id=sandbox_id),
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
|
|
125
134
|
def _finalize_channel(loop, channel):
|
|
126
135
|
if not loop.is_closed():
|
|
127
136
|
# only run if loop has not shut down
|
|
@@ -139,27 +148,19 @@ class TaskCommandRouterClient:
|
|
|
139
148
|
"""
|
|
140
149
|
|
|
141
150
|
@classmethod
|
|
142
|
-
async def
|
|
151
|
+
async def _connect(
|
|
143
152
|
cls,
|
|
144
153
|
server_client,
|
|
145
154
|
task_id: str,
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
except ConflictError:
|
|
154
|
-
logger.debug(f"Command router access is not enabled for task {task_id}")
|
|
155
|
-
return None
|
|
156
|
-
|
|
157
|
-
logger.debug(f"Using command router access for task {task_id}")
|
|
158
|
-
|
|
159
|
-
# Build and connect a channel to the task command router now that we have access info.
|
|
160
|
-
o = urllib.parse.urlparse(resp.url)
|
|
155
|
+
url: str,
|
|
156
|
+
jwt: str,
|
|
157
|
+
*,
|
|
158
|
+
sandbox_id: Optional[str] = None,
|
|
159
|
+
) -> "TaskCommandRouterClient":
|
|
160
|
+
"""Build a connected client from a jwt and url."""
|
|
161
|
+
o = urllib.parse.urlparse(url)
|
|
161
162
|
if o.scheme != "https":
|
|
162
|
-
raise ValueError(f"Task router URL must be https, got: {
|
|
163
|
+
raise ValueError(f"Task router URL must be https, got: {url}")
|
|
163
164
|
|
|
164
165
|
host, _, port_str = o.netloc.partition(":")
|
|
165
166
|
port = int(port_str) if port_str else 443
|
|
@@ -189,7 +190,38 @@ class TaskCommandRouterClient:
|
|
|
189
190
|
loop = asyncio.get_running_loop()
|
|
190
191
|
jwt_refresh_lock = asyncio.Lock()
|
|
191
192
|
|
|
192
|
-
return cls(server_client, task_id,
|
|
193
|
+
return cls(server_client, task_id, url, jwt, channel, loop, jwt_refresh_lock, sandbox_id=sandbox_id)
|
|
194
|
+
|
|
195
|
+
@classmethod
|
|
196
|
+
async def try_init(
|
|
197
|
+
cls,
|
|
198
|
+
server_client,
|
|
199
|
+
task_id: str,
|
|
200
|
+
) -> Optional["TaskCommandRouterClient"]:
|
|
201
|
+
"""Attempt to initialize a TaskCommandRouterClient by fetching direct access.
|
|
202
|
+
|
|
203
|
+
Returns None if command router access is not enabled (FAILED_PRECONDITION).
|
|
204
|
+
"""
|
|
205
|
+
try:
|
|
206
|
+
resp = await fetch_command_router_access(server_client, task_id)
|
|
207
|
+
except ConflictError:
|
|
208
|
+
logger.debug(f"Command router access is not enabled for task {task_id}")
|
|
209
|
+
return None
|
|
210
|
+
|
|
211
|
+
logger.debug(f"Using command router access for task {task_id}")
|
|
212
|
+
return await cls._connect(server_client, task_id, resp.url, resp.jwt)
|
|
213
|
+
|
|
214
|
+
@classmethod
|
|
215
|
+
async def init_v2(
|
|
216
|
+
cls,
|
|
217
|
+
server_client,
|
|
218
|
+
sandbox_id: str,
|
|
219
|
+
task_id: str,
|
|
220
|
+
) -> "TaskCommandRouterClient":
|
|
221
|
+
"""Initialize a TaskCommandRouterClient for a V2 sandbox."""
|
|
222
|
+
resp = await fetch_command_router_access_v2(server_client, sandbox_id)
|
|
223
|
+
logger.debug(f"Using command router access for sandbox {sandbox_id}")
|
|
224
|
+
return await cls._connect(server_client, task_id, resp.url, resp.jwt, sandbox_id=sandbox_id)
|
|
193
225
|
|
|
194
226
|
def __init__(
|
|
195
227
|
self,
|
|
@@ -201,6 +233,7 @@ class TaskCommandRouterClient:
|
|
|
201
233
|
loop: asyncio.AbstractEventLoop,
|
|
202
234
|
jwt_refresh_lock: asyncio.Lock,
|
|
203
235
|
*,
|
|
236
|
+
sandbox_id: Optional[str] = None,
|
|
204
237
|
stream_stdio_retry_delay_secs: float = 0.01,
|
|
205
238
|
stream_stdio_retry_delay_factor: float = 2,
|
|
206
239
|
stream_stdio_max_retries: int = 10,
|
|
@@ -213,6 +246,7 @@ class TaskCommandRouterClient:
|
|
|
213
246
|
# Attach bearer token on all requests to the worker-side router service.
|
|
214
247
|
self._server_client = server_client
|
|
215
248
|
self._task_id = task_id
|
|
249
|
+
self._sandbox_id = sandbox_id
|
|
216
250
|
self._server_url = server_url
|
|
217
251
|
self._jwt = jwt
|
|
218
252
|
self._channel = channel
|
|
@@ -237,6 +271,10 @@ class TaskCommandRouterClient:
|
|
|
237
271
|
|
|
238
272
|
self._stub = TaskCommandRouterStub(self._channel)
|
|
239
273
|
|
|
274
|
+
@property
|
|
275
|
+
def _is_v2_sandbox(self) -> bool:
|
|
276
|
+
return self._sandbox_id is not None
|
|
277
|
+
|
|
240
278
|
def _get_metadata(self):
|
|
241
279
|
return {"authorization": f"Bearer {self._jwt}"}
|
|
242
280
|
|
|
@@ -452,14 +490,21 @@ class TaskCommandRouterClient:
|
|
|
452
490
|
)
|
|
453
491
|
return
|
|
454
492
|
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
493
|
+
if self._is_v2_sandbox:
|
|
494
|
+
logger.debug(f"Refreshing JWT for exec with sandbox ID {self._sandbox_id}")
|
|
495
|
+
v2_resp = await fetch_command_router_access_v2(self._server_client, self._sandbox_id)
|
|
496
|
+
logger.debug(f"Finished refreshing JWT for exec with sandbox ID {self._sandbox_id}")
|
|
497
|
+
jwt, url = v2_resp.jwt, v2_resp.url
|
|
498
|
+
else:
|
|
499
|
+
logger.debug(f"Refreshing JWT for exec with task ID {self._task_id}")
|
|
500
|
+
v1_resp = await fetch_command_router_access(self._server_client, self._task_id)
|
|
501
|
+
logger.debug(f"Finished refreshing JWT for exec with task ID {self._task_id}")
|
|
502
|
+
jwt, url = v1_resp.jwt, v1_resp.url
|
|
458
503
|
|
|
459
504
|
# Ensure the server URL remains stable for the lifetime of this client.
|
|
460
|
-
assert
|
|
461
|
-
self._jwt =
|
|
462
|
-
self._jwt_exp = _parse_jwt_expiration(
|
|
505
|
+
assert url == self._server_url, "Task router URL changed during session"
|
|
506
|
+
self._jwt = jwt
|
|
507
|
+
self._jwt_exp = _parse_jwt_expiration(jwt)
|
|
463
508
|
|
|
464
509
|
async def _call_with_auth_retry(self, func, *args, **kwargs):
|
|
465
510
|
try:
|
|
@@ -1290,12 +1290,12 @@ class _App:
|
|
|
1290
1290
|
|
|
1291
1291
|
```python
|
|
1292
1292
|
app_a = modal.App("a")
|
|
1293
|
-
@
|
|
1293
|
+
@app_a.function()
|
|
1294
1294
|
def foo():
|
|
1295
1295
|
...
|
|
1296
1296
|
|
|
1297
1297
|
app_b = modal.App("b")
|
|
1298
|
-
@
|
|
1298
|
+
@app_b.function()
|
|
1299
1299
|
def bar():
|
|
1300
1300
|
...
|
|
1301
1301
|
|
|
@@ -618,12 +618,12 @@ class _App:
|
|
|
618
618
|
|
|
619
619
|
```python
|
|
620
620
|
app_a = modal.App("a")
|
|
621
|
-
@
|
|
621
|
+
@app_a.function()
|
|
622
622
|
def foo():
|
|
623
623
|
...
|
|
624
624
|
|
|
625
625
|
app_b = modal.App("b")
|
|
626
|
-
@
|
|
626
|
+
@app_b.function()
|
|
627
627
|
def bar():
|
|
628
628
|
...
|
|
629
629
|
|
|
@@ -1334,12 +1334,12 @@ class App:
|
|
|
1334
1334
|
|
|
1335
1335
|
```python
|
|
1336
1336
|
app_a = modal.App("a")
|
|
1337
|
-
@
|
|
1337
|
+
@app_a.function()
|
|
1338
1338
|
def foo():
|
|
1339
1339
|
...
|
|
1340
1340
|
|
|
1341
1341
|
app_b = modal.App("b")
|
|
1342
|
-
@
|
|
1342
|
+
@app_b.function()
|
|
1343
1343
|
def bar():
|
|
1344
1344
|
...
|
|
1345
1345
|
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
# Copyright Modal Labs 2022
|
|
2
2
|
import re
|
|
3
|
+
import sys
|
|
4
|
+
import time
|
|
5
|
+
import warnings
|
|
3
6
|
from datetime import datetime, timedelta, timezone
|
|
4
|
-
from typing import Optional, Union
|
|
7
|
+
from typing import Optional, Union, get_args
|
|
5
8
|
|
|
9
|
+
import click
|
|
6
10
|
import rich
|
|
7
11
|
import typer
|
|
8
12
|
from click import UsageError
|
|
@@ -11,10 +15,13 @@ from rich.text import Text
|
|
|
11
15
|
from typer import Argument
|
|
12
16
|
|
|
13
17
|
from modal._object import _get_environment_name
|
|
18
|
+
from modal._traceback import print_server_warnings
|
|
14
19
|
from modal._utils.async_utils import synchronizer
|
|
15
20
|
from modal._utils.browser_utils import open_url_and_display
|
|
16
21
|
from modal.client import _Client
|
|
17
22
|
from modal.environments import ensure_env
|
|
23
|
+
from modal.output import OutputManager
|
|
24
|
+
from modal.runner import DEPLOYMENT_STRATEGY_TYPE, _stop_and_wait_for_containers
|
|
18
25
|
from modal_proto import api_pb2
|
|
19
26
|
|
|
20
27
|
from .._logs import _FETCH_LIMIT, _MAX_FETCH_RANGE, LogsFilters
|
|
@@ -464,3 +471,62 @@ async def dashboard(
|
|
|
464
471
|
|
|
465
472
|
url = f"https://modal.com/id/{app_id}"
|
|
466
473
|
open_url_and_display(url, "App dashboard")
|
|
474
|
+
|
|
475
|
+
|
|
476
|
+
@app_cli.command("rollover", no_args_is_help=True, context_settings={"ignore_unknown_options": True})
|
|
477
|
+
@synchronizer.create_blocking
|
|
478
|
+
async def rollover(
|
|
479
|
+
app_identifier: str = APP_IDENTIFIER,
|
|
480
|
+
*,
|
|
481
|
+
strategy: str = typer.Option(
|
|
482
|
+
"rolling",
|
|
483
|
+
help="Strategy for rollover",
|
|
484
|
+
click_type=click.Choice(get_args(DEPLOYMENT_STRATEGY_TYPE)),
|
|
485
|
+
),
|
|
486
|
+
env: Optional[str] = ENV_OPTION,
|
|
487
|
+
):
|
|
488
|
+
"""Rollover an App.
|
|
489
|
+
|
|
490
|
+
A rollover replaces existing containers with fresh ones built from the same
|
|
491
|
+
App version — useful for refreshing containers without changing your code.
|
|
492
|
+
The rollover appears as a new entry in the App's deployment history.
|
|
493
|
+
|
|
494
|
+
**Examples:**
|
|
495
|
+
|
|
496
|
+
Rollover an App using a rolling deployment. Running containers are now considered
|
|
497
|
+
outdated and new containers will replace them.
|
|
498
|
+
|
|
499
|
+
```
|
|
500
|
+
modal app rollover my-app
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
Rollover an App by termatining all running containers. Inputs on the queue will
|
|
504
|
+
start new containers.
|
|
505
|
+
|
|
506
|
+
```
|
|
507
|
+
modal app rollover my-app --strategy recreate
|
|
508
|
+
```
|
|
509
|
+
"""
|
|
510
|
+
env = ensure_env(env)
|
|
511
|
+
output_mgr = OutputManager.get()
|
|
512
|
+
output_mgr.print(f"🔨 Starting app rollover with {strategy} strategy")
|
|
513
|
+
t0 = time.monotonic()
|
|
514
|
+
|
|
515
|
+
client = await _Client.from_env()
|
|
516
|
+
app_id = await get_app_id.aio(app_identifier, env, client)
|
|
517
|
+
|
|
518
|
+
req = api_pb2.AppRolloverRequest(app_id=app_id)
|
|
519
|
+
response = await client.stub.AppRollover(req)
|
|
520
|
+
print_server_warnings(response.server_warnings)
|
|
521
|
+
|
|
522
|
+
if strategy == "recreate":
|
|
523
|
+
try:
|
|
524
|
+
await _stop_and_wait_for_containers(client, app_id, response.deployed_at, env)
|
|
525
|
+
except Exception as exc:
|
|
526
|
+
warnings.warn(f"App updated successfully, but containers did not all terminate. {exc}", UserWarning)
|
|
527
|
+
output_mgr.print(f"\nView Deployment: [magenta]{response.url}[/magenta]")
|
|
528
|
+
sys.exit(1)
|
|
529
|
+
|
|
530
|
+
duration = time.monotonic() - t0
|
|
531
|
+
output_mgr.step_completed(f"Rollover completed in {duration:.3f}s with {strategy} strategy! 🎉")
|
|
532
|
+
output_mgr.print(f"\nView Deployment: [magenta]{response.url}[/magenta]")
|
|
@@ -40,8 +40,11 @@ class ImportRef:
|
|
|
40
40
|
# app [+ function/entrypoint on that app]
|
|
41
41
|
object_path: str = dataclasses.field(default="")
|
|
42
42
|
|
|
43
|
+
# modal command that was invoked, so that we can provide helpful error messages
|
|
44
|
+
command: str = dataclasses.field(default="")
|
|
43
45
|
|
|
44
|
-
|
|
46
|
+
|
|
47
|
+
def parse_import_ref(object_ref: str, use_module_mode: bool = False, command: str = "") -> ImportRef:
|
|
45
48
|
if object_ref.find("::") > 1:
|
|
46
49
|
file_or_module, object_path = object_ref.split("::", 1)
|
|
47
50
|
elif object_ref.find(":") > 1:
|
|
@@ -49,7 +52,7 @@ def parse_import_ref(object_ref: str, use_module_mode: bool = False) -> ImportRe
|
|
|
49
52
|
else:
|
|
50
53
|
file_or_module, object_path = object_ref, ""
|
|
51
54
|
|
|
52
|
-
return ImportRef(file_or_module, use_module_mode, object_path)
|
|
55
|
+
return ImportRef(file_or_module, use_module_mode, object_path, command)
|
|
53
56
|
|
|
54
57
|
|
|
55
58
|
DEFAULT_APP_NAME = "app"
|
|
@@ -94,6 +97,22 @@ def import_file_or_module(import_ref: ImportRef, base_cmd: str = ""):
|
|
|
94
97
|
assert spec.loader
|
|
95
98
|
spec.loader.exec_module(module)
|
|
96
99
|
except Exception as exc:
|
|
100
|
+
if isinstance(exc, ImportError) and "attempted relative import with no known parent package" in str(exc):
|
|
101
|
+
if import_ref.file_or_module and import_ref.command and not import_ref.use_module_mode:
|
|
102
|
+
file_path = Path(import_ref.file_or_module)
|
|
103
|
+
suggested_module_path = ".".join(file_path.parts).removesuffix(".py").lstrip(".")
|
|
104
|
+
suffix = f"::{import_ref.object_path}" if import_ref.object_path else ""
|
|
105
|
+
new_message = (
|
|
106
|
+
"The source file contains relative imports and is therefore written as "
|
|
107
|
+
"part of a Python package, but Modal was invoked in script mode "
|
|
108
|
+
f"(`{import_ref.command} {import_ref.file_or_module}{suffix}`). "
|
|
109
|
+
"Try invoking Modal in module mode instead, i.e. "
|
|
110
|
+
f"`{import_ref.command} -m {suggested_module_path}{suffix}`, "
|
|
111
|
+
"assuming that your path starts at the root of the package."
|
|
112
|
+
)
|
|
113
|
+
new_exc = InvalidError(new_message)
|
|
114
|
+
new_exc.__traceback__ = exc.__traceback__
|
|
115
|
+
raise _CliUserExecutionError(str(full_path)) from new_exc
|
|
97
116
|
raise _CliUserExecutionError(str(full_path)) from exc
|
|
98
117
|
|
|
99
118
|
return module
|
|
@@ -407,7 +407,7 @@ class RunGroup(click.Group):
|
|
|
407
407
|
ctx.ensure_object(dict)
|
|
408
408
|
ctx.obj["env"] = ensure_env(ctx.params["env"])
|
|
409
409
|
|
|
410
|
-
import_ref = parse_import_ref(func_ref, use_module_mode=ctx.params["m"])
|
|
410
|
+
import_ref = parse_import_ref(func_ref, use_module_mode=ctx.params["m"], command="modal run")
|
|
411
411
|
runnable, all_usable_commands = import_and_filter(
|
|
412
412
|
import_ref, base_cmd="modal run", accept_local_entrypoint=True, accept_webhook=False
|
|
413
413
|
)
|
|
@@ -517,7 +517,7 @@ def deploy(
|
|
|
517
517
|
# this ensures that lookups without environment specification use the same env as specified
|
|
518
518
|
env = ensure_env(env)
|
|
519
519
|
|
|
520
|
-
import_ref = parse_import_ref(app_ref, use_module_mode=use_module_mode)
|
|
520
|
+
import_ref = parse_import_ref(app_ref, use_module_mode=use_module_mode, command="modal deploy")
|
|
521
521
|
|
|
522
522
|
OutputManager.get().set_timestamps(timestamps)
|
|
523
523
|
app = import_app_from_ref(import_ref, base_cmd="modal deploy")
|
|
@@ -568,7 +568,7 @@ def serve(
|
|
|
568
568
|
|
|
569
569
|
"""
|
|
570
570
|
env = ensure_env(env)
|
|
571
|
-
import_ref = parse_import_ref(app_ref, use_module_mode=use_module_mode)
|
|
571
|
+
import_ref = parse_import_ref(app_ref, use_module_mode=use_module_mode, command="modal serve")
|
|
572
572
|
|
|
573
573
|
OutputManager.get().set_timestamps(timestamps)
|
|
574
574
|
app = import_app_from_ref(import_ref, base_cmd="modal serve")
|
|
@@ -140,7 +140,7 @@ def _start_shell_in_running_container(ref: str, cmd: str, pty: bool) -> None:
|
|
|
140
140
|
|
|
141
141
|
|
|
142
142
|
def _function_spec_from_ref(ref: str, use_module_mode: bool) -> _FunctionSpec:
|
|
143
|
-
import_ref = parse_import_ref(ref, use_module_mode=use_module_mode)
|
|
143
|
+
import_ref = parse_import_ref(ref, use_module_mode=use_module_mode, command="modal shell")
|
|
144
144
|
runnable, all_usable_commands = import_and_filter(
|
|
145
145
|
import_ref,
|
|
146
146
|
base_cmd="modal shell",
|
|
@@ -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.dev2",
|
|
39
39
|
):
|
|
40
40
|
"""mdmd:hidden
|
|
41
41
|
The Modal client object is not intended to be instantiated directly by users.
|
|
@@ -171,7 +171,7 @@ class Client:
|
|
|
171
171
|
server_url: str,
|
|
172
172
|
client_type: int,
|
|
173
173
|
credentials: typing.Optional[tuple[str, str]],
|
|
174
|
-
version: str = "1.4.2.
|
|
174
|
+
version: str = "1.4.2.dev2",
|
|
175
175
|
):
|
|
176
176
|
"""mdmd:hidden
|
|
177
177
|
The Modal client object is not intended to be instantiated directly by users.
|
|
@@ -136,12 +136,13 @@ def _agent_environment() -> Optional[str]:
|
|
|
136
136
|
# Tool-specific environment variables
|
|
137
137
|
_TOOL_SPECIFIC_ENV_VARS: list[tuple[str, str]] = [
|
|
138
138
|
("CLAUDECODE", "claude-code"),
|
|
139
|
+
("CODEX_THREAD_ID", "codex"),
|
|
139
140
|
("GEMINI_CLI", "gemini-cli"),
|
|
140
141
|
("CURSOR_AGENT", "cursor"),
|
|
141
142
|
("CLINE_ACTIVE", "cline"),
|
|
142
143
|
("AUGMENT_AGENT", "augment"),
|
|
143
144
|
("OPENCODE_CLIENT", "opencode"),
|
|
144
|
-
("GOOSE_TERMINAL", "goose"),
|
|
145
|
+
("GOOSE_TERMINAL", "goose"), # honk
|
|
145
146
|
("TRAE_AI_SHELL_ID", "trae"),
|
|
146
147
|
]
|
|
147
148
|
for env_var, agent_name in _TOOL_SPECIFIC_ENV_VARS:
|
|
@@ -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."""
|
|
@@ -1187,9 +1187,13 @@ class _Sandbox(_Object, type_prefix="sb"):
|
|
|
1187
1187
|
|
|
1188
1188
|
async def _get_command_router_client(self, task_id: str) -> Optional[TaskCommandRouterClient]:
|
|
1189
1189
|
if self._command_router_client is None:
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1190
|
+
if self._is_v2:
|
|
1191
|
+
self._command_router_client = await TaskCommandRouterClient.init_v2(
|
|
1192
|
+
self._client, self.object_id, task_id
|
|
1193
|
+
)
|
|
1194
|
+
else:
|
|
1195
|
+
# Returns None if command router access is not enabled for this sandbox.
|
|
1196
|
+
self._command_router_client = await TaskCommandRouterClient.try_init(self._client, task_id)
|
|
1193
1197
|
return self._command_router_client
|
|
1194
1198
|
|
|
1195
1199
|
@property
|
|
@@ -1267,7 +1271,6 @@ class _Sandbox(_Object, type_prefix="sb"):
|
|
|
1267
1271
|
print(line)
|
|
1268
1272
|
```
|
|
1269
1273
|
"""
|
|
1270
|
-
self._ensure_v1("exec")
|
|
1271
1274
|
if pty_info is not None or _pty_info is not None:
|
|
1272
1275
|
deprecation_warning(
|
|
1273
1276
|
(2025, 9, 12),
|
|
@@ -51,6 +51,10 @@ class ModalClientBase(abc.ABC):
|
|
|
51
51
|
async def AppGetLayout(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.AppGetLayoutRequest, modal_proto.api_pb2.AppGetLayoutResponse]') -> None:
|
|
52
52
|
pass
|
|
53
53
|
|
|
54
|
+
@abc.abstractmethod
|
|
55
|
+
async def AppGetLifecycle(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.AppGetLifecycleRequest, modal_proto.api_pb2.AppGetLifecycleResponse]') -> None:
|
|
56
|
+
pass
|
|
57
|
+
|
|
54
58
|
@abc.abstractmethod
|
|
55
59
|
async def AppGetLogs(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.AppGetLogsRequest, modal_proto.api_pb2.TaskLogsBatch]') -> None:
|
|
56
60
|
pass
|
|
@@ -87,6 +91,10 @@ class ModalClientBase(abc.ABC):
|
|
|
87
91
|
async def AppRollback(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.AppRollbackRequest, google.protobuf.empty_pb2.Empty]') -> None:
|
|
88
92
|
pass
|
|
89
93
|
|
|
94
|
+
@abc.abstractmethod
|
|
95
|
+
async def AppRollover(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.AppRolloverRequest, modal_proto.api_pb2.AppRolloverResponse]') -> None:
|
|
96
|
+
pass
|
|
97
|
+
|
|
90
98
|
@abc.abstractmethod
|
|
91
99
|
async def AppSetObjects(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.AppSetObjectsRequest, google.protobuf.empty_pb2.Empty]') -> None:
|
|
92
100
|
pass
|
|
@@ -675,6 +683,10 @@ class ModalClientBase(abc.ABC):
|
|
|
675
683
|
async def TaskResult(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.TaskResultRequest, google.protobuf.empty_pb2.Empty]') -> None:
|
|
676
684
|
pass
|
|
677
685
|
|
|
686
|
+
@abc.abstractmethod
|
|
687
|
+
async def TemplateList(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.TemplateListRequest, modal_proto.api_pb2.TemplateListResponse]') -> None:
|
|
688
|
+
pass
|
|
689
|
+
|
|
678
690
|
@abc.abstractmethod
|
|
679
691
|
async def TokenFlowCreate(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.TokenFlowCreateRequest, modal_proto.api_pb2.TokenFlowCreateResponse]') -> None:
|
|
680
692
|
pass
|
|
@@ -829,6 +841,12 @@ class ModalClientBase(abc.ABC):
|
|
|
829
841
|
modal_proto.api_pb2.AppGetLayoutRequest,
|
|
830
842
|
modal_proto.api_pb2.AppGetLayoutResponse,
|
|
831
843
|
),
|
|
844
|
+
'/modal.client.ModalClient/AppGetLifecycle': grpclib.const.Handler(
|
|
845
|
+
self.AppGetLifecycle,
|
|
846
|
+
grpclib.const.Cardinality.UNARY_UNARY,
|
|
847
|
+
modal_proto.api_pb2.AppGetLifecycleRequest,
|
|
848
|
+
modal_proto.api_pb2.AppGetLifecycleResponse,
|
|
849
|
+
),
|
|
832
850
|
'/modal.client.ModalClient/AppGetLogs': grpclib.const.Handler(
|
|
833
851
|
self.AppGetLogs,
|
|
834
852
|
grpclib.const.Cardinality.UNARY_STREAM,
|
|
@@ -883,6 +901,12 @@ class ModalClientBase(abc.ABC):
|
|
|
883
901
|
modal_proto.api_pb2.AppRollbackRequest,
|
|
884
902
|
google.protobuf.empty_pb2.Empty,
|
|
885
903
|
),
|
|
904
|
+
'/modal.client.ModalClient/AppRollover': grpclib.const.Handler(
|
|
905
|
+
self.AppRollover,
|
|
906
|
+
grpclib.const.Cardinality.UNARY_UNARY,
|
|
907
|
+
modal_proto.api_pb2.AppRolloverRequest,
|
|
908
|
+
modal_proto.api_pb2.AppRolloverResponse,
|
|
909
|
+
),
|
|
886
910
|
'/modal.client.ModalClient/AppSetObjects': grpclib.const.Handler(
|
|
887
911
|
self.AppSetObjects,
|
|
888
912
|
grpclib.const.Cardinality.UNARY_UNARY,
|
|
@@ -1765,6 +1789,12 @@ class ModalClientBase(abc.ABC):
|
|
|
1765
1789
|
modal_proto.api_pb2.TaskResultRequest,
|
|
1766
1790
|
google.protobuf.empty_pb2.Empty,
|
|
1767
1791
|
),
|
|
1792
|
+
'/modal.client.ModalClient/TemplateList': grpclib.const.Handler(
|
|
1793
|
+
self.TemplateList,
|
|
1794
|
+
grpclib.const.Cardinality.UNARY_UNARY,
|
|
1795
|
+
modal_proto.api_pb2.TemplateListRequest,
|
|
1796
|
+
modal_proto.api_pb2.TemplateListResponse,
|
|
1797
|
+
),
|
|
1768
1798
|
'/modal.client.ModalClient/TokenFlowCreate': grpclib.const.Handler(
|
|
1769
1799
|
self.TokenFlowCreate,
|
|
1770
1800
|
grpclib.const.Cardinality.UNARY_UNARY,
|
|
@@ -1975,6 +2005,12 @@ class ModalClientStub:
|
|
|
1975
2005
|
modal_proto.api_pb2.AppGetLayoutRequest,
|
|
1976
2006
|
modal_proto.api_pb2.AppGetLayoutResponse,
|
|
1977
2007
|
)
|
|
2008
|
+
self.AppGetLifecycle = grpclib.client.UnaryUnaryMethod(
|
|
2009
|
+
channel,
|
|
2010
|
+
'/modal.client.ModalClient/AppGetLifecycle',
|
|
2011
|
+
modal_proto.api_pb2.AppGetLifecycleRequest,
|
|
2012
|
+
modal_proto.api_pb2.AppGetLifecycleResponse,
|
|
2013
|
+
)
|
|
1978
2014
|
self.AppGetLogs = grpclib.client.UnaryStreamMethod(
|
|
1979
2015
|
channel,
|
|
1980
2016
|
'/modal.client.ModalClient/AppGetLogs',
|
|
@@ -2029,6 +2065,12 @@ class ModalClientStub:
|
|
|
2029
2065
|
modal_proto.api_pb2.AppRollbackRequest,
|
|
2030
2066
|
google.protobuf.empty_pb2.Empty,
|
|
2031
2067
|
)
|
|
2068
|
+
self.AppRollover = grpclib.client.UnaryUnaryMethod(
|
|
2069
|
+
channel,
|
|
2070
|
+
'/modal.client.ModalClient/AppRollover',
|
|
2071
|
+
modal_proto.api_pb2.AppRolloverRequest,
|
|
2072
|
+
modal_proto.api_pb2.AppRolloverResponse,
|
|
2073
|
+
)
|
|
2032
2074
|
self.AppSetObjects = grpclib.client.UnaryUnaryMethod(
|
|
2033
2075
|
channel,
|
|
2034
2076
|
'/modal.client.ModalClient/AppSetObjects',
|
|
@@ -2911,6 +2953,12 @@ class ModalClientStub:
|
|
|
2911
2953
|
modal_proto.api_pb2.TaskResultRequest,
|
|
2912
2954
|
google.protobuf.empty_pb2.Empty,
|
|
2913
2955
|
)
|
|
2956
|
+
self.TemplateList = grpclib.client.UnaryUnaryMethod(
|
|
2957
|
+
channel,
|
|
2958
|
+
'/modal.client.ModalClient/TemplateList',
|
|
2959
|
+
modal_proto.api_pb2.TemplateListRequest,
|
|
2960
|
+
modal_proto.api_pb2.TemplateListResponse,
|
|
2961
|
+
)
|
|
2914
2962
|
self.TokenFlowCreate = grpclib.client.UnaryUnaryMethod(
|
|
2915
2963
|
channel,
|
|
2916
2964
|
'/modal.client.ModalClient/TokenFlowCreate',
|