modal 1.5.3.dev3__tar.gz → 1.5.3.dev4__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.3.dev3 → modal-1.5.3.dev4}/PKG-INFO +1 -1
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_container_entrypoint.py +2 -4
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_runtime/container_io_manager.py +6 -30
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_runtime/container_io_manager.pyi +5 -16
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/client.py +13 -7
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/client.pyi +15 -13
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/config.py +28 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/functions.pyi +6 -6
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/sandbox.py +33 -4
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/sandbox.pyi +75 -12
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal.egg-info/PKG-INFO +1 -1
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal_proto/api_pb2.py +1143 -1143
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal_proto/api_pb2.pyi +27 -19
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal_proto/task_command_router_grpc.py +16 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal_proto/task_command_router_pb2.py +33 -13
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal_proto/task_command_router_pb2.pyi +31 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal_proto/task_command_router_pb2_grpc.py +37 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal_proto/task_command_router_pb2_grpc.pyi +20 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal_version/__init__.py +1 -1
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/LICENSE +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/README.md +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/__init__.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/__main__.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_billing.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_clustered_functions.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_clustered_functions.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_environments.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_function_variants.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_functions.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_grpc_client.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_image.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_ipython.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_load_context.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_location.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_logs.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_object.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_output/__init__.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_output/manager.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_output/pty.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_output/rich.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_output/status.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_partial_function.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_resolver.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_resources.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_runtime/__init__.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_runtime/asgi.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_runtime/execution_context.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_runtime/execution_context.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_runtime/gpu_memory_snapshot.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_runtime/task_lifecycle_manager.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_runtime/task_lifecycle_manager.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_runtime/telemetry.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_runtime/user_code_event_loop.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_runtime/user_code_imports.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_serialization.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_server.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_traceback.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_tunnel.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_tunnel.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_type_manager.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_utils/__init__.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_utils/app_utils.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_utils/async_utils.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_utils/auth_token_manager.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_utils/blob_utils.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_utils/browser_utils.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_utils/bytes_io_segment_payload.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_utils/curl_utils.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_utils/deprecation.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_utils/docker_utils.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_utils/function_utils.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_utils/git_utils.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_utils/grpc_testing.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_utils/grpc_utils.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_utils/hash_utils.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_utils/http_utils.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_utils/jwt_utils.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_utils/logger.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_utils/mount_utils.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_utils/name_utils.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_utils/package_utils.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_utils/pattern_utils.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_utils/proxy_support.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_utils/rand_pb_testing.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_utils/sandbox_fs_utils.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_utils/shell_utils.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_utils/task_command_router_client.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_utils/time_utils.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_vendor/__init__.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_vendor/a2wsgi_wsgi.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_vendor/cloudpickle.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_vendor/tblib.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_vendor/version.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_watcher.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/_workspace.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/app.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/app.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/billing.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/billing.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/builder/2023.12.312.txt +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/builder/2023.12.txt +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/builder/2024.04.txt +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/builder/2024.10.txt +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/builder/2025.06.txt +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/builder/PREVIEW.txt +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/builder/README.md +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/builder/base-images.json +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/call_graph.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/cli/__init__.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/cli/_download.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/cli/_help.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/cli/_traceback.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/cli/app.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/cli/billing.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/cli/bootstrap.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/cli/changelog.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/cli/cluster.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/cli/config.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/cli/container.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/cli/curl.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/cli/dashboard.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/cli/dict.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/cli/endpoint.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/cli/entry_point.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/cli/environment.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/cli/image.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/cli/import_refs.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/cli/launch.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/cli/logo.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/cli/network_file_system.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/cli/profile.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/cli/programs/__init__.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/cli/programs/run_jupyter.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/cli/programs/vscode.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/cli/queues.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/cli/run.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/cli/secret.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/cli/selector.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/cli/shell.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/cli/skills.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/cli/token.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/cli/utils.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/cli/volume.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/cli/workspace.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/cloud_bucket_mount.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/cloud_bucket_mount.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/cls.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/cls.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/container_process.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/container_process.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/dict.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/dict.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/environments.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/environments.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/exception.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/experimental/__init__.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/experimental/flash.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/experimental/flash.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/experimental/ipython.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/file_io.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/file_io.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/file_pattern_matcher.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/functions.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/image.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/image.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/io_streams.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/io_streams.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/mount.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/mount.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/network_file_system.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/network_file_system.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/object.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/object.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/output.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/parallel_map.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/parallel_map.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/partial_function.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/partial_function.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/proxy.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/proxy.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/py.typed +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/queue.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/queue.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/retries.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/runner.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/runner.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/running_app.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/sandbox_fs.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/sandbox_fs.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/schedule.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/scheduler_placement.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/secret.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/secret.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/server.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/server.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/serving.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/serving.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/skills/modal/SKILL.md +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/snapshot.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/snapshot.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/stream_type.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/token_flow.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/token_flow.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/types.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/volume.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/volume.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/workspace.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal/workspace.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal.egg-info/SOURCES.txt +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal.egg-info/dependency_links.txt +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal.egg-info/entry_points.txt +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal.egg-info/requires.txt +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal.egg-info/top_level.txt +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal_docs/__init__.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal_docs/gen_cli_docs.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal_docs/gen_cli_docs_main.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal_docs/gen_reference_docs.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal_docs/gen_reference_docs_main.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal_docs/mdmd/__init__.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal_docs/mdmd/mdmd.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal_docs/mdmd/signatures.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal_docs/mdmd/types.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal_proto/__init__.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal_proto/api_grpc.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal_proto/api_pb2_grpc.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal_proto/api_pb2_grpc.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal_proto/modal_api_grpc.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal_proto/py.typed +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/modal_version/__main__.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/pyproject.toml +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev4}/setup.cfg +0 -0
|
@@ -145,7 +145,7 @@ def call_function(
|
|
|
145
145
|
item_count += 1
|
|
146
146
|
|
|
147
147
|
await container_io_manager._send_outputs.aio(
|
|
148
|
-
|
|
148
|
+
io_context.output_items_generator_done(started_at, item_count)
|
|
149
149
|
)
|
|
150
150
|
else:
|
|
151
151
|
value = await io_context.call_function_async()
|
|
@@ -182,9 +182,7 @@ def call_function(
|
|
|
182
182
|
container_io_manager._queue_put(generator_queue, value)
|
|
183
183
|
item_count += 1
|
|
184
184
|
|
|
185
|
-
container_io_manager._send_outputs(
|
|
186
|
-
started_at, io_context.output_items_generator_done(started_at, item_count)
|
|
187
|
-
)
|
|
185
|
+
container_io_manager._send_outputs(io_context.output_items_generator_done(started_at, item_count))
|
|
188
186
|
else:
|
|
189
187
|
values = io_context.call_function_sync()
|
|
190
188
|
container_io_manager.push_outputs(io_context, started_at, values)
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
# Copyright Modal Labs 2024
|
|
2
2
|
import asyncio
|
|
3
3
|
import inspect
|
|
4
|
-
import math
|
|
5
4
|
import sys
|
|
6
5
|
import time
|
|
7
6
|
import traceback
|
|
@@ -48,8 +47,6 @@ DYNAMIC_CONCURRENCY_INTERVAL_SECS = 3
|
|
|
48
47
|
DYNAMIC_CONCURRENCY_TIMEOUT_SECS = 10
|
|
49
48
|
MAX_OUTPUT_BATCH_SIZE: int = 49
|
|
50
49
|
|
|
51
|
-
RTT_S: float = 0.5 # conservative estimate of RTT in seconds.
|
|
52
|
-
|
|
53
50
|
|
|
54
51
|
class Sentinel:
|
|
55
52
|
"""Used to get type-stubs to work with this object."""
|
|
@@ -474,8 +471,6 @@ class _ContainerIOManager:
|
|
|
474
471
|
_task_lifecycle_manager: _TaskLifecycleManager
|
|
475
472
|
input_plane_server_url: str | None
|
|
476
473
|
|
|
477
|
-
calls_completed: int
|
|
478
|
-
total_user_time: float
|
|
479
474
|
current_input_id: str | None
|
|
480
475
|
current_inputs: dict[str, IOContext] # input_id -> IOContext
|
|
481
476
|
current_input_started_at: float | None
|
|
@@ -510,8 +505,6 @@ class _ContainerIOManager:
|
|
|
510
505
|
|
|
511
506
|
self.input_plane_server_url = container_args.input_plane_server_url
|
|
512
507
|
|
|
513
|
-
self.calls_completed = 0
|
|
514
|
-
self.total_user_time = 0.0
|
|
515
508
|
self.current_input_id = None
|
|
516
509
|
self.current_inputs = {}
|
|
517
510
|
self.current_input_started_at = None
|
|
@@ -791,18 +784,6 @@ class _ContainerIOManager:
|
|
|
791
784
|
"""Put a value onto a queue, using the synchronicity event loop."""
|
|
792
785
|
await queue.put(value)
|
|
793
786
|
|
|
794
|
-
def get_average_call_time(self) -> float:
|
|
795
|
-
if self.calls_completed == 0:
|
|
796
|
-
return 0
|
|
797
|
-
|
|
798
|
-
return self.total_user_time / self.calls_completed
|
|
799
|
-
|
|
800
|
-
def get_max_inputs_to_fetch(self):
|
|
801
|
-
if self.calls_completed == 0:
|
|
802
|
-
return 1
|
|
803
|
-
|
|
804
|
-
return math.ceil(RTT_S / max(self.get_average_call_time(), 1e-6))
|
|
805
|
-
|
|
806
787
|
@synchronizer.no_io_translation
|
|
807
788
|
async def _generate_inputs(
|
|
808
789
|
self,
|
|
@@ -814,8 +795,6 @@ class _ContainerIOManager:
|
|
|
814
795
|
while self._fetching_inputs:
|
|
815
796
|
await self._input_slots.acquire()
|
|
816
797
|
|
|
817
|
-
request.average_call_time = self.get_average_call_time()
|
|
818
|
-
request.max_values = self.get_max_inputs_to_fetch() # Deprecated; remove.
|
|
819
798
|
request.input_concurrency = self.get_input_concurrency()
|
|
820
799
|
request.batch_max_size, request.batch_linger_ms = batch_max_size, batch_wait_ms
|
|
821
800
|
|
|
@@ -888,7 +867,7 @@ class _ContainerIOManager:
|
|
|
888
867
|
# collect all active input slots, meaning all inputs have wrapped up.
|
|
889
868
|
await self._input_slots.close()
|
|
890
869
|
|
|
891
|
-
async def _send_outputs(self,
|
|
870
|
+
async def _send_outputs(self, outputs: list[api_pb2.FunctionPutOutputsItem]) -> None:
|
|
892
871
|
"""Send pre-built output items with retry and chunking."""
|
|
893
872
|
# There are multiple outputs for a single IOContext in the case of @modal.batched.
|
|
894
873
|
# Limit the batch size to 20 to stay within message size limits and buffer size limits.
|
|
@@ -902,7 +881,7 @@ class _ContainerIOManager:
|
|
|
902
881
|
),
|
|
903
882
|
)
|
|
904
883
|
input_ids = [output.input_id for output in outputs]
|
|
905
|
-
self.exit_context(
|
|
884
|
+
self.exit_context(input_ids)
|
|
906
885
|
|
|
907
886
|
@asynccontextmanager
|
|
908
887
|
async def handle_input_exception(
|
|
@@ -922,7 +901,7 @@ class _ContainerIOManager:
|
|
|
922
901
|
raise
|
|
923
902
|
except (InputCancellation, asyncio.CancelledError):
|
|
924
903
|
outputs = await io_context.output_items_cancellation(started_at)
|
|
925
|
-
await self._send_outputs(
|
|
904
|
+
await self._send_outputs(outputs)
|
|
926
905
|
logger.warning(f"Successfully canceled input {io_context.input_ids}")
|
|
927
906
|
return
|
|
928
907
|
except BaseException as exc:
|
|
@@ -933,12 +912,9 @@ class _ContainerIOManager:
|
|
|
933
912
|
# print exception so it's logged
|
|
934
913
|
print_exception(*sys.exc_info())
|
|
935
914
|
outputs = await io_context.output_items_exception(started_at, self.task_id, exc)
|
|
936
|
-
await self._send_outputs(
|
|
937
|
-
|
|
938
|
-
def exit_context(self, started_at, input_ids: list[str]):
|
|
939
|
-
self.total_user_time += time.time() - started_at
|
|
940
|
-
self.calls_completed += 1
|
|
915
|
+
await self._send_outputs(outputs)
|
|
941
916
|
|
|
917
|
+
def exit_context(self, input_ids: list[str]):
|
|
942
918
|
for input_id in input_ids:
|
|
943
919
|
self.current_inputs.pop(input_id)
|
|
944
920
|
|
|
@@ -954,7 +930,7 @@ class _ContainerIOManager:
|
|
|
954
930
|
) -> None:
|
|
955
931
|
# The standard output encoding+sending method for successful function outputs
|
|
956
932
|
outputs = await io_context.output_items(started_at, output_data)
|
|
957
|
-
await self._send_outputs(
|
|
933
|
+
await self._send_outputs(outputs)
|
|
958
934
|
|
|
959
935
|
@asynccontextmanager
|
|
960
936
|
async def snapshot_context_manager(self) -> AsyncGenerator[None, None]:
|
|
@@ -100,8 +100,6 @@ class _ContainerIOManager:
|
|
|
100
100
|
app_id: str
|
|
101
101
|
_task_lifecycle_manager: modal._runtime.task_lifecycle_manager._TaskLifecycleManager
|
|
102
102
|
input_plane_server_url: typing.Optional[str]
|
|
103
|
-
calls_completed: int
|
|
104
|
-
total_user_time: float
|
|
105
103
|
current_input_id: typing.Optional[str]
|
|
106
104
|
current_inputs: dict[str, IOContext]
|
|
107
105
|
current_input_started_at: typing.Optional[float]
|
|
@@ -185,8 +183,6 @@ class _ContainerIOManager:
|
|
|
185
183
|
"""Put a value onto a queue, using the synchronicity event loop."""
|
|
186
184
|
...
|
|
187
185
|
|
|
188
|
-
def get_average_call_time(self) -> float: ...
|
|
189
|
-
def get_max_inputs_to_fetch(self): ...
|
|
190
186
|
def _generate_inputs(
|
|
191
187
|
self, batch_max_size: int, batch_wait_ms: int
|
|
192
188
|
) -> collections.abc.AsyncIterator[list[tuple[str, int, str, str, modal_proto.api_pb2.FunctionInput]]]: ...
|
|
@@ -196,7 +192,7 @@ class _ContainerIOManager:
|
|
|
196
192
|
batch_max_size: int = 0,
|
|
197
193
|
batch_wait_ms: int = 0,
|
|
198
194
|
) -> collections.abc.AsyncIterator[IOContext]: ...
|
|
199
|
-
async def _send_outputs(self,
|
|
195
|
+
async def _send_outputs(self, outputs: list[modal_proto.api_pb2.FunctionPutOutputsItem]) -> None:
|
|
200
196
|
"""Send pre-built output items with retry and chunking."""
|
|
201
197
|
...
|
|
202
198
|
|
|
@@ -204,7 +200,7 @@ class _ContainerIOManager:
|
|
|
204
200
|
"""Handle an exception while processing a function input."""
|
|
205
201
|
...
|
|
206
202
|
|
|
207
|
-
def exit_context(self,
|
|
203
|
+
def exit_context(self, input_ids: list[str]): ...
|
|
208
204
|
async def push_outputs(self, io_context: IOContext, started_at: float, output_data: list[typing.Any]) -> None: ...
|
|
209
205
|
def snapshot_context_manager(self) -> typing.AsyncContextManager[None]: ...
|
|
210
206
|
async def interact(self, from_breakpoint: bool = False): ...
|
|
@@ -246,8 +242,6 @@ class ContainerIOManager:
|
|
|
246
242
|
app_id: str
|
|
247
243
|
_task_lifecycle_manager: modal._runtime.task_lifecycle_manager.TaskLifecycleManager
|
|
248
244
|
input_plane_server_url: typing.Optional[str]
|
|
249
|
-
calls_completed: int
|
|
250
|
-
total_user_time: float
|
|
251
245
|
current_input_id: typing.Optional[str]
|
|
252
246
|
current_inputs: dict[str, IOContext]
|
|
253
247
|
current_input_started_at: typing.Optional[float]
|
|
@@ -413,9 +407,6 @@ class ContainerIOManager:
|
|
|
413
407
|
|
|
414
408
|
_queue_put: ___queue_put_spec
|
|
415
409
|
|
|
416
|
-
def get_average_call_time(self) -> float: ...
|
|
417
|
-
def get_max_inputs_to_fetch(self): ...
|
|
418
|
-
|
|
419
410
|
class ___generate_inputs_spec(typing_extensions.Protocol):
|
|
420
411
|
def __call__(
|
|
421
412
|
self, /, batch_max_size: int, batch_wait_ms: int
|
|
@@ -445,11 +436,11 @@ class ContainerIOManager:
|
|
|
445
436
|
run_inputs_outputs: __run_inputs_outputs_spec
|
|
446
437
|
|
|
447
438
|
class ___send_outputs_spec(typing_extensions.Protocol):
|
|
448
|
-
def __call__(self, /,
|
|
439
|
+
def __call__(self, /, outputs: list[modal_proto.api_pb2.FunctionPutOutputsItem]) -> None:
|
|
449
440
|
"""Send pre-built output items with retry and chunking."""
|
|
450
441
|
...
|
|
451
442
|
|
|
452
|
-
async def aio(self, /,
|
|
443
|
+
async def aio(self, /, outputs: list[modal_proto.api_pb2.FunctionPutOutputsItem]) -> None:
|
|
453
444
|
"""Send pre-built output items with retry and chunking."""
|
|
454
445
|
...
|
|
455
446
|
|
|
@@ -468,7 +459,7 @@ class ContainerIOManager:
|
|
|
468
459
|
|
|
469
460
|
handle_input_exception: __handle_input_exception_spec
|
|
470
461
|
|
|
471
|
-
def exit_context(self,
|
|
462
|
+
def exit_context(self, input_ids: list[str]): ...
|
|
472
463
|
|
|
473
464
|
class __push_outputs_spec(typing_extensions.Protocol):
|
|
474
465
|
def __call__(self, /, io_context: IOContext, started_at: float, output_data: list[typing.Any]) -> None: ...
|
|
@@ -517,5 +508,3 @@ class ContainerIOManager:
|
|
|
517
508
|
def stop_fetching_inputs(cls): ...
|
|
518
509
|
|
|
519
510
|
MAX_OUTPUT_BATCH_SIZE: int
|
|
520
|
-
|
|
521
|
-
RTT_S: float
|
|
@@ -6,7 +6,7 @@ import sys
|
|
|
6
6
|
import urllib.parse
|
|
7
7
|
import warnings
|
|
8
8
|
from collections.abc import AsyncGenerator, Collection, Mapping
|
|
9
|
-
from typing import Any, ClassVar, TypeVar
|
|
9
|
+
from typing import Any, ClassVar, Coroutine, TypeVar
|
|
10
10
|
|
|
11
11
|
import grpclib.client
|
|
12
12
|
from google.protobuf import empty_pb2
|
|
@@ -41,7 +41,7 @@ def _get_metadata(client_type: int, credentials: tuple[str, str] | None, version
|
|
|
41
41
|
# sys.version_info is structured unlike sys.version or platform.python_version()
|
|
42
42
|
python_version = "%d.%d.%d" % (sys.version_info.major, sys.version_info.minor, sys.version_info.micro)
|
|
43
43
|
|
|
44
|
-
metadata = {
|
|
44
|
+
metadata: dict[str, str] = {
|
|
45
45
|
"x-modal-client-version": version,
|
|
46
46
|
"x-modal-client-type": str(client_type),
|
|
47
47
|
"x-modal-python-version": python_version,
|
|
@@ -58,9 +58,15 @@ def _get_metadata(client_type: int, credentials: tuple[str, str] | None, version
|
|
|
58
58
|
)
|
|
59
59
|
if agent_env := _agent_environment():
|
|
60
60
|
metadata["x-modal-agent-harness"] = urllib.parse.quote(agent_env)
|
|
61
|
+
|
|
62
|
+
override_headers = config.get("override_headers")
|
|
63
|
+
if override_headers:
|
|
64
|
+
metadata.update(override_headers)
|
|
65
|
+
|
|
61
66
|
return metadata
|
|
62
67
|
|
|
63
68
|
|
|
69
|
+
T = TypeVar("T")
|
|
64
70
|
ReturnType = TypeVar("ReturnType")
|
|
65
71
|
_Value = str | bytes
|
|
66
72
|
_MetadataLike = Mapping[str, _Value] | Collection[tuple[str, _Value]]
|
|
@@ -308,7 +314,7 @@ class _Client:
|
|
|
308
314
|
("x-modal-auth-token", token),
|
|
309
315
|
]
|
|
310
316
|
|
|
311
|
-
async def _call_safely(self, coro, readable_method: str):
|
|
317
|
+
async def _call_safely(self, coro: Coroutine[Any, Any, T], readable_method: str) -> T:
|
|
312
318
|
"""Runs coroutine wrapped in a task that's part of the client's task context
|
|
313
319
|
|
|
314
320
|
* Raises ClientClosed in case the client is closed while the coroutine is executed
|
|
@@ -364,11 +370,11 @@ class _Client:
|
|
|
364
370
|
async def _call_unary(
|
|
365
371
|
self,
|
|
366
372
|
grpclib_method: grpclib.client.UnaryUnaryMethod[RequestType, ResponseType],
|
|
367
|
-
request:
|
|
373
|
+
request: RequestType,
|
|
368
374
|
*,
|
|
369
375
|
timeout: float | None = None,
|
|
370
376
|
metadata: _MetadataLike | None = None,
|
|
371
|
-
) ->
|
|
377
|
+
) -> ResponseType:
|
|
372
378
|
coro = grpclib_method(request, timeout=timeout, metadata=metadata)
|
|
373
379
|
return await self._call_safely(coro, grpclib_method.name)
|
|
374
380
|
|
|
@@ -376,10 +382,10 @@ class _Client:
|
|
|
376
382
|
async def _call_stream(
|
|
377
383
|
self,
|
|
378
384
|
grpclib_method: grpclib.client.UnaryStreamMethod[RequestType, ResponseType],
|
|
379
|
-
request:
|
|
385
|
+
request: RequestType,
|
|
380
386
|
*,
|
|
381
387
|
metadata: _MetadataLike | None,
|
|
382
|
-
) -> AsyncGenerator[
|
|
388
|
+
) -> AsyncGenerator[ResponseType, None]:
|
|
383
389
|
stream_context = grpclib_method.open(metadata=metadata)
|
|
384
390
|
stream = await self._call_safely(stream_context.__aenter__(), f"{grpclib_method.name}.open")
|
|
385
391
|
try:
|
|
@@ -13,6 +13,8 @@ import typing_extensions
|
|
|
13
13
|
|
|
14
14
|
def _get_metadata(client_type: int, credentials: typing.Optional[tuple[str, str]], version: str) -> dict[str, str]: ...
|
|
15
15
|
|
|
16
|
+
T = typing.TypeVar("T")
|
|
17
|
+
|
|
16
18
|
ReturnType = typing.TypeVar("ReturnType")
|
|
17
19
|
|
|
18
20
|
RequestType = typing.TypeVar("RequestType", bound="google.protobuf.message.Message")
|
|
@@ -35,7 +37,7 @@ class _Client:
|
|
|
35
37
|
server_url: str,
|
|
36
38
|
client_type: int,
|
|
37
39
|
credentials: typing.Optional[tuple[str, str]],
|
|
38
|
-
version: str = "1.5.3.
|
|
40
|
+
version: str = "1.5.3.dev4",
|
|
39
41
|
):
|
|
40
42
|
"""mdmd:hidden
|
|
41
43
|
The Modal client object is not intended to be instantiated directly by users.
|
|
@@ -154,7 +156,7 @@ class _Client:
|
|
|
154
156
|
"""
|
|
155
157
|
...
|
|
156
158
|
|
|
157
|
-
async def _call_safely(self, coro, readable_method: str):
|
|
159
|
+
async def _call_safely(self, coro: typing.Coroutine[typing.Any, typing.Any, T], readable_method: str) -> T:
|
|
158
160
|
"""Runs coroutine wrapped in a task that's part of the client's task context
|
|
159
161
|
|
|
160
162
|
* Raises ClientClosed in case the client is closed while the coroutine is executed
|
|
@@ -168,7 +170,7 @@ class _Client:
|
|
|
168
170
|
async def _call_unary(
|
|
169
171
|
self,
|
|
170
172
|
grpclib_method: grpclib.client.UnaryUnaryMethod[RequestType, ResponseType],
|
|
171
|
-
request:
|
|
173
|
+
request: RequestType,
|
|
172
174
|
*,
|
|
173
175
|
timeout: typing.Optional[float] = None,
|
|
174
176
|
metadata: typing.Union[
|
|
@@ -176,18 +178,18 @@ class _Client:
|
|
|
176
178
|
collections.abc.Collection[tuple[str, typing.Union[str, bytes]]],
|
|
177
179
|
None,
|
|
178
180
|
] = None,
|
|
179
|
-
) ->
|
|
181
|
+
) -> ResponseType: ...
|
|
180
182
|
def _call_stream(
|
|
181
183
|
self,
|
|
182
184
|
grpclib_method: grpclib.client.UnaryStreamMethod[RequestType, ResponseType],
|
|
183
|
-
request:
|
|
185
|
+
request: RequestType,
|
|
184
186
|
*,
|
|
185
187
|
metadata: typing.Union[
|
|
186
188
|
collections.abc.Mapping[str, typing.Union[str, bytes]],
|
|
187
189
|
collections.abc.Collection[tuple[str, typing.Union[str, bytes]]],
|
|
188
190
|
None,
|
|
189
191
|
],
|
|
190
|
-
) -> collections.abc.AsyncGenerator[
|
|
192
|
+
) -> collections.abc.AsyncGenerator[ResponseType, None]: ...
|
|
191
193
|
|
|
192
194
|
class Client:
|
|
193
195
|
_client_from_env: typing.ClassVar[typing.Optional[Client]]
|
|
@@ -205,7 +207,7 @@ class Client:
|
|
|
205
207
|
server_url: str,
|
|
206
208
|
client_type: int,
|
|
207
209
|
credentials: typing.Optional[tuple[str, str]],
|
|
208
|
-
version: str = "1.5.3.
|
|
210
|
+
version: str = "1.5.3.dev4",
|
|
209
211
|
):
|
|
210
212
|
"""mdmd:hidden
|
|
211
213
|
The Modal client object is not intended to be instantiated directly by users.
|
|
@@ -429,7 +431,7 @@ class Client:
|
|
|
429
431
|
get_input_plane_metadata: __get_input_plane_metadata_spec
|
|
430
432
|
|
|
431
433
|
class ___call_safely_spec(typing_extensions.Protocol):
|
|
432
|
-
def __call__(self, /, coro, readable_method: str):
|
|
434
|
+
def __call__(self, /, coro: T, readable_method: str) -> T:
|
|
433
435
|
"""Runs coroutine wrapped in a task that's part of the client's task context
|
|
434
436
|
|
|
435
437
|
* Raises ClientClosed in case the client is closed while the coroutine is executed
|
|
@@ -438,7 +440,7 @@ class Client:
|
|
|
438
440
|
"""
|
|
439
441
|
...
|
|
440
442
|
|
|
441
|
-
async def aio(self, /, coro, readable_method: str):
|
|
443
|
+
async def aio(self, /, coro: typing.Coroutine[typing.Any, typing.Any, T], readable_method: str) -> T:
|
|
442
444
|
"""Runs coroutine wrapped in a task that's part of the client's task context
|
|
443
445
|
|
|
444
446
|
* Raises ClientClosed in case the client is closed while the coroutine is executed
|
|
@@ -464,7 +466,7 @@ class Client:
|
|
|
464
466
|
async def _call_unary(
|
|
465
467
|
self,
|
|
466
468
|
grpclib_method: grpclib.client.UnaryUnaryMethod[RequestType, ResponseType],
|
|
467
|
-
request:
|
|
469
|
+
request: RequestType,
|
|
468
470
|
*,
|
|
469
471
|
timeout: typing.Optional[float] = None,
|
|
470
472
|
metadata: typing.Union[
|
|
@@ -472,18 +474,18 @@ class Client:
|
|
|
472
474
|
collections.abc.Collection[tuple[str, typing.Union[str, bytes]]],
|
|
473
475
|
None,
|
|
474
476
|
] = None,
|
|
475
|
-
) ->
|
|
477
|
+
) -> ResponseType: ...
|
|
476
478
|
def _call_stream(
|
|
477
479
|
self,
|
|
478
480
|
grpclib_method: grpclib.client.UnaryStreamMethod[RequestType, ResponseType],
|
|
479
|
-
request:
|
|
481
|
+
request: RequestType,
|
|
480
482
|
*,
|
|
481
483
|
metadata: typing.Union[
|
|
482
484
|
collections.abc.Mapping[str, typing.Union[str, bytes]],
|
|
483
485
|
collections.abc.Collection[tuple[str, typing.Union[str, bytes]]],
|
|
484
486
|
None,
|
|
485
487
|
],
|
|
486
|
-
) -> collections.abc.AsyncGenerator[
|
|
488
|
+
) -> collections.abc.AsyncGenerator[ResponseType, None]: ...
|
|
487
489
|
|
|
488
490
|
HEARTBEAT_INTERVAL: float
|
|
489
491
|
|
|
@@ -264,6 +264,33 @@ def _enforce_suffix_rules(x: str) -> str:
|
|
|
264
264
|
return x
|
|
265
265
|
|
|
266
266
|
|
|
267
|
+
def _transform_headers(s: str) -> dict[str, str]:
|
|
268
|
+
error_msg = (
|
|
269
|
+
"Must be a comma-separated list of `<header>:<value>` pairs (whitespace is ignored). "
|
|
270
|
+
"<header> and <value> must contain at least one non-whitespace character, and may "
|
|
271
|
+
"not contain commas."
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
if s == "":
|
|
275
|
+
return {}
|
|
276
|
+
|
|
277
|
+
pairs = s.split(",")
|
|
278
|
+
|
|
279
|
+
headers: dict[str, str] = {}
|
|
280
|
+
for pair in pairs:
|
|
281
|
+
res = pair.split(":", maxsplit=1)
|
|
282
|
+
if len(res) != 2:
|
|
283
|
+
raise ValueError(error_msg)
|
|
284
|
+
|
|
285
|
+
header, value = res[0].strip(), res[1].strip()
|
|
286
|
+
if len(header) == 0 or len(value) == 0:
|
|
287
|
+
raise ValueError(error_msg)
|
|
288
|
+
|
|
289
|
+
headers[header] = value
|
|
290
|
+
|
|
291
|
+
return headers
|
|
292
|
+
|
|
293
|
+
|
|
267
294
|
class _Setting(typing.NamedTuple):
|
|
268
295
|
default: typing.Any = None
|
|
269
296
|
transform: typing.Callable[[str], typing.Any] = lambda x: x # noqa: E731
|
|
@@ -306,6 +333,7 @@ _SETTINGS = {
|
|
|
306
333
|
"max_throttle_wait": _Setting(None, transform=lambda x: int(x) if x else None),
|
|
307
334
|
"async_warnings": _Setting(True, transform=_to_boolean), # Activate synchronicity usage warnings
|
|
308
335
|
"disable_api_proxy": _Setting(False, transform=_to_boolean),
|
|
336
|
+
"override_headers": _Setting(None, transform=_transform_headers),
|
|
309
337
|
}
|
|
310
338
|
|
|
311
339
|
|
|
@@ -493,7 +493,7 @@ class Function(
|
|
|
493
493
|
|
|
494
494
|
_call_generator: ___call_generator_spec
|
|
495
495
|
|
|
496
|
-
class __remote_spec(typing_extensions.Protocol[
|
|
496
|
+
class __remote_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER]):
|
|
497
497
|
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> ReturnType_INNER:
|
|
498
498
|
"""Calls the function remotely, executing it with the given arguments and returning the execution's result.
|
|
499
499
|
|
|
@@ -518,7 +518,7 @@ class Function(
|
|
|
518
518
|
"""
|
|
519
519
|
...
|
|
520
520
|
|
|
521
|
-
remote: __remote_spec[modal._functions.
|
|
521
|
+
remote: __remote_spec[modal._functions.P, modal._functions.ReturnType]
|
|
522
522
|
|
|
523
523
|
class __remote_gen_spec(typing_extensions.Protocol):
|
|
524
524
|
def __call__(self, /, *args, **kwargs) -> typing.Generator[typing.Any, None, None]:
|
|
@@ -568,7 +568,7 @@ class Function(
|
|
|
568
568
|
"""
|
|
569
569
|
...
|
|
570
570
|
|
|
571
|
-
class ___experimental_spawn_spec(typing_extensions.Protocol[
|
|
571
|
+
class ___experimental_spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER]):
|
|
572
572
|
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
|
|
573
573
|
"""[Experimental] Calls the function with the given arguments, without waiting for the results.
|
|
574
574
|
|
|
@@ -601,7 +601,7 @@ class Function(
|
|
|
601
601
|
"""
|
|
602
602
|
...
|
|
603
603
|
|
|
604
|
-
_experimental_spawn: ___experimental_spawn_spec[modal._functions.
|
|
604
|
+
_experimental_spawn: ___experimental_spawn_spec[modal._functions.P, modal._functions.ReturnType]
|
|
605
605
|
|
|
606
606
|
class ___spawn_map_inner_spec(typing_extensions.Protocol[P_INNER]):
|
|
607
607
|
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> None: ...
|
|
@@ -609,7 +609,7 @@ class Function(
|
|
|
609
609
|
|
|
610
610
|
_spawn_map_inner: ___spawn_map_inner_spec[modal._functions.P]
|
|
611
611
|
|
|
612
|
-
class __spawn_spec(typing_extensions.Protocol[
|
|
612
|
+
class __spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER]):
|
|
613
613
|
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
|
|
614
614
|
"""Calls the function with the given arguments, without waiting for the results.
|
|
615
615
|
|
|
@@ -642,7 +642,7 @@ class Function(
|
|
|
642
642
|
"""
|
|
643
643
|
...
|
|
644
644
|
|
|
645
|
-
spawn: __spawn_spec[modal._functions.
|
|
645
|
+
spawn: __spawn_spec[modal._functions.P, modal._functions.ReturnType]
|
|
646
646
|
|
|
647
647
|
def get_raw_f(self) -> collections.abc.Callable[..., typing.Any]:
|
|
648
648
|
"""Return the inner Python object wrapped by this Modal Function.
|
|
@@ -842,6 +842,7 @@ class _Sandbox(_Object, type_prefix="sb"):
|
|
|
842
842
|
experimental_options: dict[str, Any] | None = None,
|
|
843
843
|
include_oidc_identity_token: bool = False,
|
|
844
844
|
verbose: bool = False,
|
|
845
|
+
custom_domain: str | None = None,
|
|
845
846
|
client: _Client | None = None,
|
|
846
847
|
) -> "_Sandbox":
|
|
847
848
|
"""Create a sandbox using the V2 backend.
|
|
@@ -849,15 +850,17 @@ class _Sandbox(_Object, type_prefix="sb"):
|
|
|
849
850
|
Supported features include exec, encrypted tunnels, wait/poll/terminate,
|
|
850
851
|
CPU and memory configuration, region placement, private IPv6 networking
|
|
851
852
|
(i6pn), volumes, cloud bucket mounts (with static credentials via
|
|
852
|
-
`secret=...` or `oidc_auth_role_arn`), OIDC identity tokens, proxies,
|
|
853
|
-
filesystem snapshots
|
|
853
|
+
`secret=...` or `oidc_auth_role_arn`), OIDC identity tokens, proxies,
|
|
854
|
+
filesystem snapshots, and custom domains (`custom_domain=...` allows
|
|
855
|
+
connections to the sandbox via a subdomain of that parent domain rather
|
|
856
|
+
than a default Modal domain; requires prior setup by Modal).
|
|
854
857
|
|
|
855
858
|
`cpu` and `memory` accept either a scalar request or a `(request, limit)`
|
|
856
859
|
tuple that additionally sets a hard limit (fractional CPU cores; memory
|
|
857
860
|
in MiB), matching `Sandbox.create()`.
|
|
858
861
|
|
|
859
|
-
Features like memory snapshots, network file systems, GPUs
|
|
860
|
-
|
|
862
|
+
Features like memory snapshots, network file systems, and GPUs are not
|
|
863
|
+
supported.
|
|
861
864
|
|
|
862
865
|
Set `i6pn=True` to enable private IPv6 networking so sandboxes in the same
|
|
863
866
|
workspace can address each other directly at their `i6pn.modal.local`
|
|
@@ -996,6 +999,7 @@ class _Sandbox(_Object, type_prefix="sb"):
|
|
|
996
999
|
experimental_options_v2=(
|
|
997
1000
|
{k: str(v) for k, v in experimental_options.items()} if experimental_options else None
|
|
998
1001
|
),
|
|
1002
|
+
custom_domain=custom_domain,
|
|
999
1003
|
)
|
|
1000
1004
|
|
|
1001
1005
|
tag_protos = [api_pb2.SandboxTag(tag_name=k, tag_value=v) for k, v in tags.items()] if tags else []
|
|
@@ -1317,6 +1321,31 @@ class _Sandbox(_Object, type_prefix="sb"):
|
|
|
1317
1321
|
)
|
|
1318
1322
|
await stub.SandboxTagsSet(req)
|
|
1319
1323
|
|
|
1324
|
+
async def _experimental_set_name(self, name: str) -> None:
|
|
1325
|
+
"""Assign a name to a running V2 Sandbox that was created without one.
|
|
1326
|
+
|
|
1327
|
+
This is only supported for V2 sandboxes, ie sandboxes created via
|
|
1328
|
+
`modal.Sandbox._experimental_create`. A name may only be set once and
|
|
1329
|
+
only on a Sandbox that has never had one; afterwards the Sandbox can
|
|
1330
|
+
be looked up with `Sandbox._experimental_from_name(app_name, name)`.
|
|
1331
|
+
|
|
1332
|
+
Args:
|
|
1333
|
+
name: Name to assign to the Sandbox. Must be unique within the App.
|
|
1334
|
+
|
|
1335
|
+
Raises:
|
|
1336
|
+
AlreadyExistsError: If another running Sandbox in the App already holds the name.
|
|
1337
|
+
ConflictError: If the Sandbox already has a name or is no longer running.
|
|
1338
|
+
"""
|
|
1339
|
+
self._ensure_attached()
|
|
1340
|
+
if not self._is_v2:
|
|
1341
|
+
raise InvalidError("Sandbox._experimental_set_name() is only supported for V2 sandboxes")
|
|
1342
|
+
check_object_name(name, "Sandbox")
|
|
1343
|
+
|
|
1344
|
+
req = api_pb2.SandboxSetNameRequest(sandbox_id=self.object_id, name=name)
|
|
1345
|
+
assert self._client._auth_token_manager
|
|
1346
|
+
auth_token = await self._client._auth_token_manager.get_token()
|
|
1347
|
+
await self._client.stub.SandboxSetName(req, metadata=[("x-modal-auth-token", auth_token)])
|
|
1348
|
+
|
|
1320
1349
|
async def _experimental_set_outbound_network_policy(
|
|
1321
1350
|
self,
|
|
1322
1351
|
*,
|