modal 1.5.3.dev3__tar.gz → 1.5.3.dev5__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.dev5}/PKG-INFO +1 -1
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_container_entrypoint.py +2 -4
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_environments.py +18 -39
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_runtime/container_io_manager.py +6 -30
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_runtime/container_io_manager.pyi +5 -16
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/client.py +13 -7
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/client.pyi +15 -13
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/config.py +28 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/environments.pyi +8 -8
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/functions.pyi +6 -6
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/sandbox.py +41 -8
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/sandbox.pyi +75 -12
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal.egg-info/PKG-INFO +1 -1
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal_proto/api_grpc.py +16 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal_proto/api_pb2.py +1163 -1143
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal_proto/api_pb2.pyi +90 -29
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal_proto/api_pb2_grpc.py +33 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal_proto/api_pb2_grpc.pyi +10 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal_proto/modal_api_grpc.py +1 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal_proto/task_command_router_grpc.py +16 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal_proto/task_command_router_pb2.py +33 -13
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal_proto/task_command_router_pb2.pyi +31 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal_proto/task_command_router_pb2_grpc.py +37 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal_proto/task_command_router_pb2_grpc.pyi +20 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal_version/__init__.py +1 -1
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/LICENSE +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/README.md +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/__init__.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/__main__.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_billing.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_clustered_functions.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_clustered_functions.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_function_variants.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_functions.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_grpc_client.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_image.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_ipython.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_load_context.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_location.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_logs.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_object.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_output/__init__.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_output/manager.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_output/pty.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_output/rich.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_output/status.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_partial_function.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_resolver.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_resources.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_runtime/__init__.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_runtime/asgi.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_runtime/execution_context.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_runtime/execution_context.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_runtime/gpu_memory_snapshot.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_runtime/task_lifecycle_manager.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_runtime/task_lifecycle_manager.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_runtime/telemetry.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_runtime/user_code_event_loop.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_runtime/user_code_imports.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_serialization.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_server.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_traceback.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_tunnel.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_tunnel.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_type_manager.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_utils/__init__.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_utils/app_utils.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_utils/async_utils.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_utils/auth_token_manager.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_utils/blob_utils.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_utils/browser_utils.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_utils/bytes_io_segment_payload.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_utils/curl_utils.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_utils/deprecation.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_utils/docker_utils.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_utils/function_utils.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_utils/git_utils.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_utils/grpc_testing.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_utils/grpc_utils.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_utils/hash_utils.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_utils/http_utils.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_utils/jwt_utils.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_utils/logger.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_utils/mount_utils.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_utils/name_utils.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_utils/package_utils.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_utils/pattern_utils.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_utils/proxy_support.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_utils/rand_pb_testing.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_utils/sandbox_fs_utils.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_utils/shell_utils.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_utils/task_command_router_client.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_utils/time_utils.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_vendor/__init__.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_vendor/a2wsgi_wsgi.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_vendor/cloudpickle.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_vendor/tblib.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_vendor/version.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_watcher.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/_workspace.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/app.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/app.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/billing.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/billing.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/builder/2023.12.312.txt +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/builder/2023.12.txt +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/builder/2024.04.txt +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/builder/2024.10.txt +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/builder/2025.06.txt +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/builder/PREVIEW.txt +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/builder/README.md +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/builder/base-images.json +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/call_graph.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/cli/__init__.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/cli/_download.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/cli/_help.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/cli/_traceback.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/cli/app.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/cli/billing.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/cli/bootstrap.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/cli/changelog.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/cli/cluster.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/cli/config.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/cli/container.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/cli/curl.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/cli/dashboard.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/cli/dict.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/cli/endpoint.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/cli/entry_point.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/cli/environment.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/cli/image.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/cli/import_refs.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/cli/launch.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/cli/logo.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/cli/network_file_system.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/cli/profile.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/cli/programs/__init__.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/cli/programs/run_jupyter.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/cli/programs/vscode.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/cli/queues.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/cli/run.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/cli/secret.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/cli/selector.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/cli/shell.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/cli/skills.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/cli/token.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/cli/utils.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/cli/volume.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/cli/workspace.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/cloud_bucket_mount.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/cloud_bucket_mount.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/cls.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/cls.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/container_process.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/container_process.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/dict.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/dict.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/environments.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/exception.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/experimental/__init__.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/experimental/flash.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/experimental/flash.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/experimental/ipython.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/file_io.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/file_io.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/file_pattern_matcher.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/functions.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/image.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/image.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/io_streams.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/io_streams.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/mount.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/mount.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/network_file_system.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/network_file_system.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/object.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/object.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/output.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/parallel_map.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/parallel_map.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/partial_function.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/partial_function.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/proxy.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/proxy.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/py.typed +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/queue.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/queue.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/retries.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/runner.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/runner.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/running_app.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/sandbox_fs.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/sandbox_fs.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/schedule.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/scheduler_placement.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/secret.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/secret.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/server.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/server.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/serving.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/serving.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/skills/modal/SKILL.md +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/snapshot.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/snapshot.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/stream_type.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/token_flow.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/token_flow.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/types.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/volume.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/volume.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/workspace.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal/workspace.pyi +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal.egg-info/SOURCES.txt +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal.egg-info/dependency_links.txt +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal.egg-info/entry_points.txt +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal.egg-info/requires.txt +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal.egg-info/top_level.txt +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal_docs/__init__.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal_docs/gen_cli_docs.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal_docs/gen_cli_docs_main.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal_docs/gen_reference_docs.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal_docs/gen_reference_docs_main.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal_docs/mdmd/__init__.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal_docs/mdmd/mdmd.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal_docs/mdmd/signatures.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal_docs/mdmd/types.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal_proto/__init__.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal_proto/py.typed +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/modal_version/__main__.py +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/pyproject.toml +0 -0
- {modal-1.5.3.dev3 → modal-1.5.3.dev5}/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)
|
|
@@ -103,26 +103,6 @@ class _EnvironmentManager:
|
|
|
103
103
|
await client.stub.EnvironmentDelete(api_pb2.EnvironmentDeleteRequest(name=name))
|
|
104
104
|
|
|
105
105
|
|
|
106
|
-
def _role_to_proto(role: str) -> "api_pb2.EnvironmentRole.ValueType":
|
|
107
|
-
match role:
|
|
108
|
-
case "viewer":
|
|
109
|
-
return api_pb2.ENVIRONMENT_ROLE_VIEWER
|
|
110
|
-
case "contributor":
|
|
111
|
-
return api_pb2.ENVIRONMENT_ROLE_CONTRIBUTOR
|
|
112
|
-
case _:
|
|
113
|
-
raise InvalidError(f"Invalid Environment role: {role!r} (expected 'viewer' or 'contributor')")
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
def _role_from_proto(proto_value: int) -> str:
|
|
117
|
-
match proto_value:
|
|
118
|
-
case api_pb2.ENVIRONMENT_ROLE_VIEWER:
|
|
119
|
-
return "viewer"
|
|
120
|
-
case api_pb2.ENVIRONMENT_ROLE_CONTRIBUTOR:
|
|
121
|
-
return "contributor"
|
|
122
|
-
case _:
|
|
123
|
-
raise ValueError(f"Unknown environment role: {proto_value}")
|
|
124
|
-
|
|
125
|
-
|
|
126
106
|
class _EnvironmentMembersManager:
|
|
127
107
|
"""mdmd:namespace
|
|
128
108
|
Namespace with methods for managing the membership of a restricted Environment.
|
|
@@ -135,31 +115,30 @@ class _EnvironmentMembersManager:
|
|
|
135
115
|
self._environment = environment
|
|
136
116
|
|
|
137
117
|
async def list(self) -> dict[Literal["users", "service_users"], dict[str, str]]:
|
|
138
|
-
"""
|
|
118
|
+
"""Enumerate the environment roles for each user and service user in the workspace.
|
|
139
119
|
|
|
140
120
|
**Examples:**
|
|
141
121
|
|
|
142
122
|
```python notest
|
|
143
|
-
members = modal.Environment.from_name("my-
|
|
123
|
+
members = modal.Environment.from_name("my-env").members.list()
|
|
144
124
|
print(members)
|
|
145
125
|
# {
|
|
146
|
-
# "users": {"alice": "contributor", "bob": "viewer"},
|
|
147
|
-
# "service_users": {"alice-bot": "contributor"},
|
|
126
|
+
# "users": {"alice": "contributor", "bob": "viewer", "carol": "contributor"},
|
|
127
|
+
# "service_users": {"alice-bot": "contributor", "ops-bot": "viewer", "ci-bot": "no-access"},
|
|
148
128
|
# }
|
|
149
129
|
```
|
|
150
130
|
"""
|
|
151
131
|
await self._environment.hydrate()
|
|
152
|
-
req = api_pb2.
|
|
153
|
-
resp = await self._environment.client.stub.
|
|
132
|
+
req = api_pb2.EnvironmentGetRolesRequest(environment_id=self._environment.object_id)
|
|
133
|
+
resp = await self._environment.client.stub.EnvironmentGetRoles(req)
|
|
154
134
|
|
|
155
135
|
users: dict[str, str] = {}
|
|
156
136
|
service_users: dict[str, str] = {}
|
|
157
137
|
for principal in resp.principal_roles:
|
|
158
|
-
role = _role_from_proto(principal.role)
|
|
159
138
|
if principal.user_id:
|
|
160
|
-
users[principal.user_name] =
|
|
139
|
+
users[principal.user_name] = principal.role_str
|
|
161
140
|
elif principal.service_user_id:
|
|
162
|
-
service_users[principal.service_user_name] =
|
|
141
|
+
service_users[principal.service_user_name] = principal.role_str
|
|
163
142
|
|
|
164
143
|
return {"users": users, "service_users": service_users}
|
|
165
144
|
|
|
@@ -188,13 +167,13 @@ class _EnvironmentMembersManager:
|
|
|
188
167
|
users = users or {}
|
|
189
168
|
service_users = service_users or {}
|
|
190
169
|
|
|
191
|
-
req = api_pb2.
|
|
192
|
-
resp = await self._environment.client.stub.
|
|
170
|
+
req = api_pb2.EnvironmentGetRolesRequest(environment_id=self._environment.object_id)
|
|
171
|
+
resp = await self._environment.client.stub.EnvironmentGetRoles(req)
|
|
193
172
|
|
|
194
|
-
#
|
|
173
|
+
# EnvironmentGetRoles returns every workspace principal
|
|
195
174
|
user_name_to_id: dict[str, str] = {}
|
|
196
175
|
service_user_name_to_id: dict[str, str] = {}
|
|
197
|
-
for principal in
|
|
176
|
+
for principal in resp.principal_roles:
|
|
198
177
|
if principal.user_id:
|
|
199
178
|
user_name_to_id[principal.user_name] = principal.user_id
|
|
200
179
|
elif principal.service_user_id:
|
|
@@ -207,7 +186,7 @@ class _EnvironmentMembersManager:
|
|
|
207
186
|
requests[f"User {name!r}"] = api_pb2.EnvironmentRoleSetRequest(
|
|
208
187
|
environment_id=self._environment.object_id,
|
|
209
188
|
user_id=user_name_to_id[name],
|
|
210
|
-
|
|
189
|
+
role_str=role,
|
|
211
190
|
)
|
|
212
191
|
for name, role in service_users.items():
|
|
213
192
|
if name not in service_user_name_to_id:
|
|
@@ -215,7 +194,7 @@ class _EnvironmentMembersManager:
|
|
|
215
194
|
requests[f"Service user {name!r}"] = api_pb2.EnvironmentRoleSetRequest(
|
|
216
195
|
environment_id=self._environment.object_id,
|
|
217
196
|
service_user_id=service_user_name_to_id[name],
|
|
218
|
-
|
|
197
|
+
role_str=role,
|
|
219
198
|
)
|
|
220
199
|
|
|
221
200
|
await self._dispatch_role_updates(requests)
|
|
@@ -242,8 +221,8 @@ class _EnvironmentMembersManager:
|
|
|
242
221
|
users = users or []
|
|
243
222
|
service_users = service_users or []
|
|
244
223
|
|
|
245
|
-
req = api_pb2.
|
|
246
|
-
resp = await self._environment.client.stub.
|
|
224
|
+
req = api_pb2.EnvironmentGetRolesRequest(environment_id=self._environment.object_id)
|
|
225
|
+
resp = await self._environment.client.stub.EnvironmentGetRoles(req)
|
|
247
226
|
|
|
248
227
|
user_name_to_id: dict[str, str] = {}
|
|
249
228
|
service_user_name_to_id: dict[str, str] = {}
|
|
@@ -256,7 +235,7 @@ class _EnvironmentMembersManager:
|
|
|
256
235
|
requests: dict[str, api_pb2.EnvironmentRoleSetRequest] = {}
|
|
257
236
|
for name in users:
|
|
258
237
|
if name not in user_name_to_id:
|
|
259
|
-
raise InvalidError(f"User {name!r}
|
|
238
|
+
raise InvalidError(f"User {name!r} not found in workspace")
|
|
260
239
|
requests[f"User {name!r}"] = api_pb2.EnvironmentRoleSetRequest(
|
|
261
240
|
environment_id=self._environment.object_id,
|
|
262
241
|
user_id=user_name_to_id[name],
|
|
@@ -264,7 +243,7 @@ class _EnvironmentMembersManager:
|
|
|
264
243
|
)
|
|
265
244
|
for name in service_users:
|
|
266
245
|
if name not in service_user_name_to_id:
|
|
267
|
-
raise InvalidError(f"Service user {name!r}
|
|
246
|
+
raise InvalidError(f"Service user {name!r} not found in workspace")
|
|
268
247
|
requests[f"Service user {name!r}"] = api_pb2.EnvironmentRoleSetRequest(
|
|
269
248
|
environment_id=self._environment.object_id,
|
|
270
249
|
service_user_id=service_user_name_to_id[name],
|
|
@@ -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.dev5",
|
|
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.dev5",
|
|
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
|
|
|
@@ -113,32 +113,32 @@ class EnvironmentMembersManager:
|
|
|
113
113
|
|
|
114
114
|
class __list_spec(typing_extensions.Protocol):
|
|
115
115
|
def __call__(self, /) -> dict[typing.Literal["users", "service_users"], dict[str, str]]:
|
|
116
|
-
"""
|
|
116
|
+
"""Enumerate the environment roles for each user and service user in the workspace.
|
|
117
117
|
|
|
118
118
|
**Examples:**
|
|
119
119
|
|
|
120
120
|
```python notest
|
|
121
|
-
members = modal.Environment.from_name("my-
|
|
121
|
+
members = modal.Environment.from_name("my-env").members.list()
|
|
122
122
|
print(members)
|
|
123
123
|
# {
|
|
124
|
-
# "users": {"alice": "contributor", "bob": "viewer"},
|
|
125
|
-
# "service_users": {"alice-bot": "contributor"},
|
|
124
|
+
# "users": {"alice": "contributor", "bob": "viewer", "carol": "contributor"},
|
|
125
|
+
# "service_users": {"alice-bot": "contributor", "ops-bot": "viewer", "ci-bot": "no-access"},
|
|
126
126
|
# }
|
|
127
127
|
```
|
|
128
128
|
"""
|
|
129
129
|
...
|
|
130
130
|
|
|
131
131
|
async def aio(self, /) -> dict[typing.Literal["users", "service_users"], dict[str, str]]:
|
|
132
|
-
"""
|
|
132
|
+
"""Enumerate the environment roles for each user and service user in the workspace.
|
|
133
133
|
|
|
134
134
|
**Examples:**
|
|
135
135
|
|
|
136
136
|
```python notest
|
|
137
|
-
members = modal.Environment.from_name("my-
|
|
137
|
+
members = modal.Environment.from_name("my-env").members.list()
|
|
138
138
|
print(members)
|
|
139
139
|
# {
|
|
140
|
-
# "users": {"alice": "contributor", "bob": "viewer"},
|
|
141
|
-
# "service_users": {"alice-bot": "contributor"},
|
|
140
|
+
# "users": {"alice": "contributor", "bob": "viewer", "carol": "contributor"},
|
|
141
|
+
# "service_users": {"alice-bot": "contributor", "ops-bot": "viewer", "ci-bot": "no-access"},
|
|
142
142
|
# }
|
|
143
143
|
```
|
|
144
144
|
"""
|