modal 1.5.4.dev8__tar.gz → 1.5.4.dev10__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.5.4.dev8 → modal-1.5.4.dev10}/PKG-INFO +1 -1
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_output/rich.py +12 -2
- modal-1.5.4.dev10/modal/_utils/auth_token_manager.py +181 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_utils/task_command_router_client.py +14 -3
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/client.pyi +2 -2
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/sandbox.py +14 -1
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/sandbox.pyi +2 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal.egg-info/PKG-INFO +1 -1
- modal-1.5.4.dev10/modal_proto/__init__.py +11 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal_proto/api_grpc.py +32 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal_proto/api_pb2.py +1193 -1153
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal_proto/api_pb2.pyi +121 -9
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal_proto/api_pb2_grpc.py +67 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal_proto/api_pb2_grpc.pyi +27 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal_proto/modal_api_grpc.py +2 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal_version/__init__.py +1 -1
- modal-1.5.4.dev8/modal/_utils/auth_token_manager.py +0 -157
- modal-1.5.4.dev8/modal_proto/__init__.py +0 -4
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/LICENSE +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/README.md +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/__init__.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/__main__.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_billing.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_clustered_functions.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_clustered_functions.pyi +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_container_entrypoint.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_environments.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_function_variants.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_functions.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_grpc_client.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_image.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_ipython.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_load_context.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_location.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_logs.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_logs_manager.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_logs_manager.pyi +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_object.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_output/__init__.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_output/manager.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_output/pty.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_output/status.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_partial_function.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_resolver.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_resources.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_runtime/__init__.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_runtime/asgi.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_runtime/container_io_manager.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_runtime/container_io_manager.pyi +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_runtime/execution_context.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_runtime/execution_context.pyi +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_runtime/gpu_memory_snapshot.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_runtime/task_lifecycle_manager.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_runtime/task_lifecycle_manager.pyi +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_runtime/telemetry.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_runtime/user_code_event_loop.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_runtime/user_code_imports.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_serialization.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_server.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_supports_logs.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_traceback.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_tunnel.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_tunnel.pyi +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_type_manager.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_utils/__init__.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_utils/app_utils.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_utils/async_utils.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_utils/blob_utils.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_utils/browser_utils.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_utils/bytes_io_segment_payload.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_utils/curl_utils.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_utils/deprecation.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_utils/display_utils.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_utils/docker_utils.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_utils/function_utils.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_utils/git_utils.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_utils/grpc_testing.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_utils/grpc_utils.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_utils/hash_utils.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_utils/http_utils.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_utils/jwt_utils.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_utils/logger.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_utils/mount_utils.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_utils/name_utils.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_utils/package_utils.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_utils/pattern_utils.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_utils/proxy_support.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_utils/rand_pb_testing.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_utils/sandbox_fs_utils.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_utils/shell_utils.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_utils/time_utils.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_vendor/__init__.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_vendor/a2wsgi_wsgi.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_vendor/cloudpickle.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_vendor/tblib.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_vendor/version.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_watcher.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/_workspace.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/app.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/app.pyi +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/billing.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/billing.pyi +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/builder/2023.12.312.txt +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/builder/2023.12.txt +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/builder/2024.04.txt +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/builder/2024.10.txt +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/builder/2025.06.txt +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/builder/PREVIEW.txt +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/builder/README.md +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/builder/base-images.json +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/call_graph.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/cli/__init__.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/cli/_download.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/cli/_help.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/cli/_traceback.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/cli/app.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/cli/billing.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/cli/bootstrap.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/cli/changelog.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/cli/cluster.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/cli/config.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/cli/container.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/cli/curl.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/cli/dashboard.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/cli/dict.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/cli/endpoint.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/cli/entry_point.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/cli/environment.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/cli/image.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/cli/import_refs.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/cli/launch.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/cli/logo.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/cli/network_file_system.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/cli/profile.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/cli/programs/__init__.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/cli/programs/run_jupyter.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/cli/programs/vscode.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/cli/queues.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/cli/run.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/cli/secret.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/cli/selector.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/cli/shell.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/cli/skills.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/cli/token.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/cli/utils.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/cli/volume.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/cli/workspace.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/client.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/cloud_bucket_mount.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/cloud_bucket_mount.pyi +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/cls.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/cls.pyi +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/config.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/container_process.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/container_process.pyi +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/dict.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/dict.pyi +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/environments.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/environments.pyi +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/exception.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/experimental/__init__.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/experimental/flash.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/experimental/flash.pyi +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/experimental/ipython.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/file_io.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/file_io.pyi +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/file_pattern_matcher.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/functions.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/functions.pyi +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/image.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/image.pyi +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/io_streams.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/io_streams.pyi +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/mount.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/mount.pyi +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/network_file_system.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/network_file_system.pyi +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/object.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/object.pyi +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/output.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/parallel_map.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/parallel_map.pyi +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/partial_function.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/partial_function.pyi +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/proxy.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/proxy.pyi +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/py.typed +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/queue.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/queue.pyi +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/retries.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/runner.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/runner.pyi +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/running_app.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/sandbox_fs.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/sandbox_fs.pyi +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/schedule.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/scheduler_placement.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/secret.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/secret.pyi +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/server.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/server.pyi +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/serving.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/serving.pyi +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/skills/modal/SKILL.md +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/snapshot.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/snapshot.pyi +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/stream_type.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/token_flow.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/token_flow.pyi +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/types.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/volume.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/volume.pyi +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/workspace.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal/workspace.pyi +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal.egg-info/SOURCES.txt +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal.egg-info/dependency_links.txt +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal.egg-info/entry_points.txt +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal.egg-info/requires.txt +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal.egg-info/top_level.txt +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal_docs/__init__.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal_docs/gen_cli_docs.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal_docs/gen_cli_docs_main.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal_docs/gen_reference_docs.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal_docs/gen_reference_docs_main.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal_docs/mdmd/__init__.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal_docs/mdmd/mdmd.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal_docs/mdmd/signatures.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal_docs/mdmd/types.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal_docs/reference_intro.md +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal_proto/py.typed +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal_proto/task_command_router_grpc.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal_proto/task_command_router_pb2.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal_proto/task_command_router_pb2.pyi +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal_proto/task_command_router_pb2_grpc.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal_proto/task_command_router_pb2_grpc.pyi +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/modal_version/__main__.py +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/pyproject.toml +0 -0
- {modal-1.5.4.dev8 → modal-1.5.4.dev10}/setup.cfg +0 -0
|
@@ -37,6 +37,7 @@ from rich.progress import (
|
|
|
37
37
|
)
|
|
38
38
|
from rich.spinner import Spinner
|
|
39
39
|
from rich.status import Status
|
|
40
|
+
from rich.table import Column
|
|
40
41
|
from rich.text import Text
|
|
41
42
|
from rich.tree import Tree
|
|
42
43
|
|
|
@@ -476,7 +477,10 @@ class RichOutputManager(OutputManager):
|
|
|
476
477
|
and adds it to the current render group."""
|
|
477
478
|
if not self._function_queueing_progress:
|
|
478
479
|
self._function_queueing_progress = Progress(
|
|
479
|
-
TextColumn(
|
|
480
|
+
TextColumn(
|
|
481
|
+
"[progress.description]{task.description}",
|
|
482
|
+
table_column=Column(no_wrap=False, overflow="fold"),
|
|
483
|
+
),
|
|
480
484
|
FunctionQueuingColumn(),
|
|
481
485
|
console=self._console,
|
|
482
486
|
transient=True,
|
|
@@ -581,11 +585,17 @@ class RichOutputManager(OutputManager):
|
|
|
581
585
|
"""Handle queueing updates, ignoring completion updates for functions that have no queue progress bar."""
|
|
582
586
|
task_key = (function_id, api_pb2.FUNCTION_QUEUED)
|
|
583
587
|
task_description = description or f"'{function_id}' function waiting on worker"
|
|
588
|
+
task_description = escape(task_description)
|
|
584
589
|
task_desc = f"[yellow]{task_description}. Time in queue:"
|
|
585
590
|
if task_key in self._task_progress_items:
|
|
586
591
|
progress_task_id = self._task_progress_items[task_key]
|
|
587
592
|
try:
|
|
588
|
-
self._function_queueing_progress_bar.update(
|
|
593
|
+
self._function_queueing_progress_bar.update(
|
|
594
|
+
progress_task_id,
|
|
595
|
+
description=task_desc if description else None,
|
|
596
|
+
completed=completed,
|
|
597
|
+
total=total,
|
|
598
|
+
)
|
|
589
599
|
if completed == total:
|
|
590
600
|
del self._task_progress_items[task_key]
|
|
591
601
|
self._function_queueing_progress_bar.remove_task(progress_task_id)
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
# Copyright Modal Labs 2025
|
|
2
|
+
import asyncio
|
|
3
|
+
import base64
|
|
4
|
+
import json
|
|
5
|
+
import random
|
|
6
|
+
import time
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
from modal._utils.grpc_utils import DEFAULT_MAX_RETRIES, Retry
|
|
10
|
+
from modal.exception import AuthError, ExecutionError, PermissionDeniedError
|
|
11
|
+
from modal_proto import api_pb2, modal_api_grpc
|
|
12
|
+
|
|
13
|
+
from .logger import logger
|
|
14
|
+
|
|
15
|
+
AUTH_DENIED_EXCEPTIONS = (AuthError, PermissionDeniedError)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class _AuthTokenManager:
|
|
19
|
+
"""Handles fetching and refreshing of the input plane auth token."""
|
|
20
|
+
|
|
21
|
+
# Fraction of the token's lifetime to use before refreshing.
|
|
22
|
+
REFRESH_FRACTION = 0.5
|
|
23
|
+
# Width of the random band added on top of REFRESH_FRACTION, so that clients issued
|
|
24
|
+
# same-lifetime tokens at the same moment (a fan-out of containers starting together)
|
|
25
|
+
# spread their refreshes out instead of refreshing in lockstep every cycle. The band
|
|
26
|
+
# only ever delays a refresh, so the margin before expiry stays at no less than
|
|
27
|
+
# 1 - REFRESH_FRACTION - REFRESH_JITTER of the lifetime.
|
|
28
|
+
REFRESH_JITTER = 0.1
|
|
29
|
+
# Bound each AuthTokenGet attempt so a refresh can't hang.
|
|
30
|
+
AUTH_TOKEN_TIMEOUT = 5.0
|
|
31
|
+
AUTH_TOKEN_RETRY_TOTAL_TIMEOUT = 3 * AUTH_TOKEN_TIMEOUT
|
|
32
|
+
# After a failed refresh, wait before hitting the server again, growing exponentially with
|
|
33
|
+
# consecutive failures between these bounds (in seconds).
|
|
34
|
+
FAILURE_BACKOFF_BASE = 0.5
|
|
35
|
+
FAILURE_BACKOFF_MAX = 60.0
|
|
36
|
+
# If the token doesn't have an expiry field, default to current time plus this value (not expected).
|
|
37
|
+
DEFAULT_EXPIRY_OFFSET = 20 * 60
|
|
38
|
+
|
|
39
|
+
def __init__(self, stub: "modal_api_grpc.ModalClientModal"):
|
|
40
|
+
self._stub = stub
|
|
41
|
+
self._token = ""
|
|
42
|
+
self._expiry = 0.0
|
|
43
|
+
self._refresh_at = 0.0
|
|
44
|
+
self._retry_after = 0.0
|
|
45
|
+
self._backoff = self.FAILURE_BACKOFF_BASE
|
|
46
|
+
self._refresh_task: asyncio.Task | None = None
|
|
47
|
+
|
|
48
|
+
async def get_token(self) -> str:
|
|
49
|
+
"""
|
|
50
|
+
When called, the AuthTokenManager can be in one of three states:
|
|
51
|
+
1. Has a valid cached token. It is returned to the caller.
|
|
52
|
+
2. Has no cached token, or the token is expired. We fetch a new one and cache it. If `get_token` is called
|
|
53
|
+
concurrently by multiple coroutines, all requests will block until the token has been fetched. But only one
|
|
54
|
+
coroutine will actually make a request to the control plane to fetch the new token. This ensures we do not hit
|
|
55
|
+
the control plane with more requests than needed.
|
|
56
|
+
3. Has a valid cached token that has used up its refresh fraction of its lifetime. In this case we fetch a new
|
|
57
|
+
token and cache it. If `get_token` is called concurrently, only one request will fetch the new token, and the
|
|
58
|
+
others will be given the old (but still valid) token - i.e. they will not block.
|
|
59
|
+
"""
|
|
60
|
+
if not self._token or self._is_expired():
|
|
61
|
+
# We either have no token or it is expired - block everyone until we get a new token
|
|
62
|
+
await self._try_refresh_token()
|
|
63
|
+
elif self._should_refresh():
|
|
64
|
+
# The token is still valid, but has used up its refresh fraction of its lifetime.
|
|
65
|
+
if self._refresh_task is not None:
|
|
66
|
+
# A refresh is in flight, so someone else is refreshing. Continue to use the old token.
|
|
67
|
+
return self._token
|
|
68
|
+
else:
|
|
69
|
+
# Nobody is refreshing, so we need to fetch a new token.
|
|
70
|
+
await self._try_refresh_token()
|
|
71
|
+
|
|
72
|
+
return self._token
|
|
73
|
+
|
|
74
|
+
async def _try_refresh_token(self):
|
|
75
|
+
try:
|
|
76
|
+
await self._refresh_token()
|
|
77
|
+
except AUTH_DENIED_EXCEPTIONS:
|
|
78
|
+
raise
|
|
79
|
+
except Exception as e:
|
|
80
|
+
if not self._token:
|
|
81
|
+
raise
|
|
82
|
+
logger.warning("Auth token refresh failed; falling back to cached token: %s", e)
|
|
83
|
+
|
|
84
|
+
async def _refresh_token(self):
|
|
85
|
+
"""
|
|
86
|
+
Fetch a new token from the control plane. Concurrent callers share a single request: the first caller starts it
|
|
87
|
+
and the others await the same task, so a burst of callers results in one RPC whether it succeeds or fails. The
|
|
88
|
+
task is owned by the event loop rather than by the caller that started it, so it runs to completion even if that
|
|
89
|
+
caller goes away.
|
|
90
|
+
"""
|
|
91
|
+
if self._refresh_task is None:
|
|
92
|
+
# Maybe another coroutine refreshed already, or we're cooling down after a failure.
|
|
93
|
+
if self._token and not self._should_refresh():
|
|
94
|
+
return
|
|
95
|
+
# Note: the task is created in async code so it binds to the synchronicity event loop.
|
|
96
|
+
self._refresh_task = asyncio.create_task(self._fetch_token())
|
|
97
|
+
self._refresh_task.add_done_callback(self._refresh_task_done)
|
|
98
|
+
# Shielded so a cancelled caller doesn't cancel the refresh for everyone else.
|
|
99
|
+
await asyncio.shield(self._refresh_task)
|
|
100
|
+
|
|
101
|
+
def _refresh_task_done(self, task: "asyncio.Task"):
|
|
102
|
+
if self._refresh_task is task:
|
|
103
|
+
self._refresh_task = None
|
|
104
|
+
if not task.cancelled():
|
|
105
|
+
# Retrieve the exception, if any, so a failure isn't logged as unhandled when no caller is waiting.
|
|
106
|
+
task.exception()
|
|
107
|
+
|
|
108
|
+
async def _fetch_token(self):
|
|
109
|
+
"""Make the AuthTokenGet request and cache its token, or arm the failure backoff."""
|
|
110
|
+
try:
|
|
111
|
+
resp: api_pb2.AuthTokenGetResponse = await self._stub.AuthTokenGet(
|
|
112
|
+
api_pb2.AuthTokenGetRequest(),
|
|
113
|
+
# No cached token to fall back on, so a failure is user-visible: retry transient errors.
|
|
114
|
+
# Otherwise one attempt, and _retry_after handles the cooldown.
|
|
115
|
+
retry=Retry(
|
|
116
|
+
attempt_timeout=self.AUTH_TOKEN_TIMEOUT,
|
|
117
|
+
total_timeout=self.AUTH_TOKEN_RETRY_TOTAL_TIMEOUT,
|
|
118
|
+
max_retries=0 if self._token else DEFAULT_MAX_RETRIES,
|
|
119
|
+
),
|
|
120
|
+
)
|
|
121
|
+
if not resp.token:
|
|
122
|
+
# Not expected
|
|
123
|
+
raise ExecutionError(
|
|
124
|
+
"Internal error: Did not receive auth token from server. Please contact Modal support."
|
|
125
|
+
)
|
|
126
|
+
if exp := self._decode_jwt(resp.token).get("exp"):
|
|
127
|
+
expiry = float(exp)
|
|
128
|
+
else:
|
|
129
|
+
# This should never happen.
|
|
130
|
+
logger.warning("x-modal-auth-token does not contain exp field")
|
|
131
|
+
expiry = time.time() + self.DEFAULT_EXPIRY_OFFSET
|
|
132
|
+
self._token = resp.token
|
|
133
|
+
self._set_expiry(expiry)
|
|
134
|
+
self._retry_after = 0.0
|
|
135
|
+
self._backoff = self.FAILURE_BACKOFF_BASE
|
|
136
|
+
except AUTH_DENIED_EXCEPTIONS:
|
|
137
|
+
raise
|
|
138
|
+
except Exception as e:
|
|
139
|
+
# Back off (exponentially on consecutive failures) so we don't hammer a struggling server.
|
|
140
|
+
self._retry_after = time.time() + self._backoff
|
|
141
|
+
self._backoff = min(self._backoff * 2, self.FAILURE_BACKOFF_MAX)
|
|
142
|
+
raise
|
|
143
|
+
|
|
144
|
+
@staticmethod
|
|
145
|
+
def _decode_jwt(token: str) -> dict[str, Any]:
|
|
146
|
+
"""
|
|
147
|
+
Decodes a JWT into a dict without verifying signature. We do this manually instead of using a library to avoid
|
|
148
|
+
adding another dependency to the client.
|
|
149
|
+
"""
|
|
150
|
+
try:
|
|
151
|
+
payload = token.split(".")[1]
|
|
152
|
+
padding = "=" * (-len(payload) % 4)
|
|
153
|
+
decoded_bytes = base64.urlsafe_b64decode(payload + padding)
|
|
154
|
+
return json.loads(decoded_bytes)
|
|
155
|
+
except Exception as e:
|
|
156
|
+
raise ValueError("Internal error: Cannot parse auth token. Please contact Modal support.") from e
|
|
157
|
+
|
|
158
|
+
def _in_backoff(self):
|
|
159
|
+
return time.time() < self._retry_after
|
|
160
|
+
|
|
161
|
+
def _should_refresh(self):
|
|
162
|
+
# Fetch only when the token is stale/expiring and we're not in a post-failure backoff.
|
|
163
|
+
return self._needs_refresh() and not self._in_backoff()
|
|
164
|
+
|
|
165
|
+
def _set_expiry(self, expiry: float) -> None:
|
|
166
|
+
"""Record a new expiry and schedule the proactive refresh a jittered fraction of the way through.
|
|
167
|
+
|
|
168
|
+
The delay is measured from the remaining lifetime as this client sees it, so a client whose clock is
|
|
169
|
+
skewed relative to the issuer still keeps a margin proportional to the lifetime it observes.
|
|
170
|
+
"""
|
|
171
|
+
now = time.time()
|
|
172
|
+
self._expiry = expiry
|
|
173
|
+
remaining = max(expiry - now, 0.0)
|
|
174
|
+
fraction = self.REFRESH_FRACTION + random.random() * self.REFRESH_JITTER
|
|
175
|
+
self._refresh_at = now + remaining * fraction
|
|
176
|
+
|
|
177
|
+
def _needs_refresh(self):
|
|
178
|
+
return time.time() >= self._refresh_at
|
|
179
|
+
|
|
180
|
+
def _is_expired(self):
|
|
181
|
+
return time.time() >= self._expiry
|
|
@@ -288,11 +288,22 @@ class TaskCommandRouterClient:
|
|
|
288
288
|
server_client,
|
|
289
289
|
sandbox_id: str,
|
|
290
290
|
task_id: str,
|
|
291
|
+
access: api_pb2.CommandRouterAccess | None = None,
|
|
291
292
|
) -> "TaskCommandRouterClient":
|
|
292
|
-
"""Initialize a TaskCommandRouterClient for a V2 sandbox.
|
|
293
|
-
|
|
293
|
+
"""Initialize a TaskCommandRouterClient for a V2 sandbox.
|
|
294
|
+
|
|
295
|
+
`access` is the router access returned by SandboxCreateV2/SandboxRestoreV2,
|
|
296
|
+
which lets a freshly scheduled sandbox connect without a round-trip. When it
|
|
297
|
+
is absent — a re-attached sandbox, or the server could not mint a token — we
|
|
298
|
+
ask for it.
|
|
299
|
+
"""
|
|
300
|
+
if access is not None:
|
|
301
|
+
url, jwt = access.url, access.jwt
|
|
302
|
+
else:
|
|
303
|
+
resp = await fetch_command_router_access_v2(server_client, sandbox_id=sandbox_id)
|
|
304
|
+
url, jwt = resp.url, resp.jwt
|
|
294
305
|
logger.debug(f"Using command router access for sandbox {sandbox_id}")
|
|
295
|
-
return await cls._connect(server_client, task_id,
|
|
306
|
+
return await cls._connect(server_client, task_id, url, jwt, sandbox_id=sandbox_id)
|
|
296
307
|
|
|
297
308
|
@classmethod
|
|
298
309
|
async def init_v2_by_task_id(
|
|
@@ -37,7 +37,7 @@ class _Client:
|
|
|
37
37
|
server_url: str,
|
|
38
38
|
client_type: int,
|
|
39
39
|
credentials: typing.Optional[tuple[str, str]],
|
|
40
|
-
version: str = "1.5.4.
|
|
40
|
+
version: str = "1.5.4.dev10",
|
|
41
41
|
):
|
|
42
42
|
"""mdmd:hidden
|
|
43
43
|
The Modal client object is not intended to be instantiated directly by users.
|
|
@@ -207,7 +207,7 @@ class Client:
|
|
|
207
207
|
server_url: str,
|
|
208
208
|
client_type: int,
|
|
209
209
|
credentials: typing.Optional[tuple[str, str]],
|
|
210
|
-
version: str = "1.5.4.
|
|
210
|
+
version: str = "1.5.4.dev10",
|
|
211
211
|
):
|
|
212
212
|
"""mdmd:hidden
|
|
213
213
|
The Modal client object is not intended to be instantiated directly by users.
|
|
@@ -333,6 +333,7 @@ class _Sandbox(_Object, type_prefix="sb"):
|
|
|
333
333
|
_tunnels: dict[int, Tunnel] | None
|
|
334
334
|
_enable_snapshot: bool
|
|
335
335
|
_command_router_client: TaskCommandRouterClient | None
|
|
336
|
+
_init_command_router_access: api_pb2.CommandRouterAccess | None
|
|
336
337
|
_attached: bool
|
|
337
338
|
_filesystem: _SandboxFilesystem | None
|
|
338
339
|
_is_v2: bool = False
|
|
@@ -1034,6 +1035,10 @@ class _Sandbox(_Object, type_prefix="sb"):
|
|
|
1034
1035
|
self._hydrate(sandbox_id, load_context.client, create_resp.metadata)
|
|
1035
1036
|
self._is_v2 = True
|
|
1036
1037
|
self._task_id = create_resp.task_id
|
|
1038
|
+
# An unset proto message reads as an empty one rather than None, so the
|
|
1039
|
+
# presence check is what distinguishes "no access" from "empty access".
|
|
1040
|
+
if create_resp.HasField("command_router_access"):
|
|
1041
|
+
self._init_command_router_access = create_resp.command_router_access
|
|
1037
1042
|
self._hydrate_metadata_v2()
|
|
1038
1043
|
# Unencrypted tunnel endpoints are not known at create time. Only
|
|
1039
1044
|
# cache a complete set so tunnels() fetches the rest otherwise.
|
|
@@ -1121,6 +1126,7 @@ class _Sandbox(_Object, type_prefix="sb"):
|
|
|
1121
1126
|
self._tunnels = None
|
|
1122
1127
|
self._enable_snapshot = False
|
|
1123
1128
|
self._command_router_client = None
|
|
1129
|
+
self._init_command_router_access = None
|
|
1124
1130
|
self._filesystem = None
|
|
1125
1131
|
self._is_v2 = _is_v2_sandbox_id(self.object_id)
|
|
1126
1132
|
if self._is_v2:
|
|
@@ -1912,8 +1918,12 @@ class _Sandbox(_Object, type_prefix="sb"):
|
|
|
1912
1918
|
if self._command_router_client is None:
|
|
1913
1919
|
try:
|
|
1914
1920
|
if self._is_v2:
|
|
1921
|
+
# Consume the seeded access, so if connecting with it fails the
|
|
1922
|
+
# retry falls back to the authoritative RPC instead of
|
|
1923
|
+
# re-trying the same credentials forever.
|
|
1924
|
+
access, self._init_command_router_access = self._init_command_router_access, None
|
|
1915
1925
|
self._command_router_client = await TaskCommandRouterClient.init_v2_by_sandbox_id(
|
|
1916
|
-
self._client, self.object_id, task_id
|
|
1926
|
+
self._client, self.object_id, task_id, access
|
|
1917
1927
|
)
|
|
1918
1928
|
else:
|
|
1919
1929
|
self._command_router_client = await TaskCommandRouterClient.init(self._client, task_id)
|
|
@@ -2278,6 +2288,9 @@ class _Sandbox(_Object, type_prefix="sb"):
|
|
|
2278
2288
|
|
|
2279
2289
|
sandbox = await _Sandbox.from_id(restore_resp.sandbox_id, client)
|
|
2280
2290
|
sandbox._task_id = restore_resp.task_id
|
|
2291
|
+
# Seeded after from_id, whose hydration resets the field.
|
|
2292
|
+
if restore_resp.HasField("command_router_access"):
|
|
2293
|
+
sandbox._init_command_router_access = restore_resp.command_router_access
|
|
2281
2294
|
return sandbox
|
|
2282
2295
|
|
|
2283
2296
|
@property
|
|
@@ -147,6 +147,7 @@ class _Sandbox(modal._object._Object):
|
|
|
147
147
|
_tunnels: typing.Optional[dict[int, modal._tunnel.Tunnel]]
|
|
148
148
|
_enable_snapshot: bool
|
|
149
149
|
_command_router_client: typing.Optional[modal._utils.task_command_router_client.TaskCommandRouterClient]
|
|
150
|
+
_init_command_router_access: typing.Optional[modal_proto.api_pb2.CommandRouterAccess]
|
|
150
151
|
_attached: bool
|
|
151
152
|
_filesystem: typing.Optional[modal.sandbox_fs._SandboxFilesystem]
|
|
152
153
|
_is_v2: bool
|
|
@@ -1454,6 +1455,7 @@ class Sandbox(modal.object.Object):
|
|
|
1454
1455
|
_tunnels: typing.Optional[dict[int, modal._tunnel.Tunnel]]
|
|
1455
1456
|
_enable_snapshot: bool
|
|
1456
1457
|
_command_router_client: typing.Optional[modal._utils.task_command_router_client.TaskCommandRouterClient]
|
|
1458
|
+
_init_command_router_access: typing.Optional[modal_proto.api_pb2.CommandRouterAccess]
|
|
1457
1459
|
_attached: bool
|
|
1458
1460
|
_filesystem: typing.Optional[modal.sandbox_fs.SandboxFilesystem]
|
|
1459
1461
|
_is_v2: bool
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Copyright Modal Labs 2024
|
|
2
|
+
"""Modal gRPC types for Python.
|
|
3
|
+
|
|
4
|
+
Warning: direct usage of Modal's gRPC API is discouraged,
|
|
5
|
+
and no support or compatibility guarantees are provided.
|
|
6
|
+
Message fields or entire RPCs may be changed or removed
|
|
7
|
+
without notice. We recommend using official SDKs instead.
|
|
8
|
+
"""
|
|
9
|
+
from pkgutil import extend_path
|
|
10
|
+
|
|
11
|
+
__path__ = extend_path(__path__, __name__) # type: ignore[has-type]
|
|
@@ -123,6 +123,10 @@ class ModalClientBase(abc.ABC):
|
|
|
123
123
|
async def AuthTokenGet(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.AuthTokenGetRequest, modal_proto.api_pb2.AuthTokenGetResponse]') -> None:
|
|
124
124
|
pass
|
|
125
125
|
|
|
126
|
+
@abc.abstractmethod
|
|
127
|
+
async def AutoscalerOverrideHistory(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.AutoscalerOverrideHistoryRequest, modal_proto.api_pb2.AutoscalerOverrideHistoryResponse]') -> None:
|
|
128
|
+
pass
|
|
129
|
+
|
|
126
130
|
@abc.abstractmethod
|
|
127
131
|
async def BlobCreate(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.BlobCreateRequest, modal_proto.api_pb2.BlobCreateResponse]') -> None:
|
|
128
132
|
pass
|
|
@@ -327,6 +331,10 @@ class ModalClientBase(abc.ABC):
|
|
|
327
331
|
async def EnvironmentSetBudget(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.EnvironmentSetBudgetRequest, google.protobuf.empty_pb2.Empty]') -> None:
|
|
328
332
|
pass
|
|
329
333
|
|
|
334
|
+
@abc.abstractmethod
|
|
335
|
+
async def EnvironmentSetDefaultMemberRole(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.EnvironmentSetDefaultMemberRoleRequest, google.protobuf.empty_pb2.Empty]') -> None:
|
|
336
|
+
pass
|
|
337
|
+
|
|
330
338
|
@abc.abstractmethod
|
|
331
339
|
async def EnvironmentSetManaged(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.EnvironmentSetManagedRequest, google.protobuf.empty_pb2.Empty]') -> None:
|
|
332
340
|
pass
|
|
@@ -1113,6 +1121,12 @@ class ModalClientBase(abc.ABC):
|
|
|
1113
1121
|
modal_proto.api_pb2.AuthTokenGetRequest,
|
|
1114
1122
|
modal_proto.api_pb2.AuthTokenGetResponse,
|
|
1115
1123
|
),
|
|
1124
|
+
'/modal.client.ModalClient/AutoscalerOverrideHistory': grpclib.const.Handler(
|
|
1125
|
+
self.AutoscalerOverrideHistory,
|
|
1126
|
+
grpclib.const.Cardinality.UNARY_UNARY,
|
|
1127
|
+
modal_proto.api_pb2.AutoscalerOverrideHistoryRequest,
|
|
1128
|
+
modal_proto.api_pb2.AutoscalerOverrideHistoryResponse,
|
|
1129
|
+
),
|
|
1116
1130
|
'/modal.client.ModalClient/BlobCreate': grpclib.const.Handler(
|
|
1117
1131
|
self.BlobCreate,
|
|
1118
1132
|
grpclib.const.Cardinality.UNARY_UNARY,
|
|
@@ -1419,6 +1433,12 @@ class ModalClientBase(abc.ABC):
|
|
|
1419
1433
|
modal_proto.api_pb2.EnvironmentSetBudgetRequest,
|
|
1420
1434
|
google.protobuf.empty_pb2.Empty,
|
|
1421
1435
|
),
|
|
1436
|
+
'/modal.client.ModalClient/EnvironmentSetDefaultMemberRole': grpclib.const.Handler(
|
|
1437
|
+
self.EnvironmentSetDefaultMemberRole,
|
|
1438
|
+
grpclib.const.Cardinality.UNARY_UNARY,
|
|
1439
|
+
modal_proto.api_pb2.EnvironmentSetDefaultMemberRoleRequest,
|
|
1440
|
+
google.protobuf.empty_pb2.Empty,
|
|
1441
|
+
),
|
|
1422
1442
|
'/modal.client.ModalClient/EnvironmentSetManaged': grpclib.const.Handler(
|
|
1423
1443
|
self.EnvironmentSetManaged,
|
|
1424
1444
|
grpclib.const.Cardinality.UNARY_UNARY,
|
|
@@ -2523,6 +2543,12 @@ class ModalClientStub:
|
|
|
2523
2543
|
modal_proto.api_pb2.AuthTokenGetRequest,
|
|
2524
2544
|
modal_proto.api_pb2.AuthTokenGetResponse,
|
|
2525
2545
|
)
|
|
2546
|
+
self.AutoscalerOverrideHistory = grpclib.client.UnaryUnaryMethod(
|
|
2547
|
+
channel,
|
|
2548
|
+
'/modal.client.ModalClient/AutoscalerOverrideHistory',
|
|
2549
|
+
modal_proto.api_pb2.AutoscalerOverrideHistoryRequest,
|
|
2550
|
+
modal_proto.api_pb2.AutoscalerOverrideHistoryResponse,
|
|
2551
|
+
)
|
|
2526
2552
|
self.BlobCreate = grpclib.client.UnaryUnaryMethod(
|
|
2527
2553
|
channel,
|
|
2528
2554
|
'/modal.client.ModalClient/BlobCreate',
|
|
@@ -2829,6 +2855,12 @@ class ModalClientStub:
|
|
|
2829
2855
|
modal_proto.api_pb2.EnvironmentSetBudgetRequest,
|
|
2830
2856
|
google.protobuf.empty_pb2.Empty,
|
|
2831
2857
|
)
|
|
2858
|
+
self.EnvironmentSetDefaultMemberRole = grpclib.client.UnaryUnaryMethod(
|
|
2859
|
+
channel,
|
|
2860
|
+
'/modal.client.ModalClient/EnvironmentSetDefaultMemberRole',
|
|
2861
|
+
modal_proto.api_pb2.EnvironmentSetDefaultMemberRoleRequest,
|
|
2862
|
+
google.protobuf.empty_pb2.Empty,
|
|
2863
|
+
)
|
|
2832
2864
|
self.EnvironmentSetManaged = grpclib.client.UnaryUnaryMethod(
|
|
2833
2865
|
channel,
|
|
2834
2866
|
'/modal.client.ModalClient/EnvironmentSetManaged',
|