modal 1.5.6.dev24__tar.gz → 1.5.6.dev26__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.6.dev24 → modal-1.5.6.dev26}/PKG-INFO +1 -1
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/__init__.py +4 -3
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_clustered_functions.py +1 -1
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_environments.py +72 -15
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_function_variants.py +4 -4
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_functions.py +48 -25
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_image.py +7 -7
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_logs.py +5 -5
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_logs_manager.py +2 -2
- modal-1.5.6.dev24/modal/outbound_policy.py → modal-1.5.6.dev26/modal/_outbound_policy.py +10 -4
- modal-1.5.6.dev24/modal/outbound_policy.pyi → modal-1.5.6.dev26/modal/_outbound_policy.pyi +10 -4
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_output/pty.py +2 -2
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_partial_function.py +45 -30
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_runtime/container_io_manager.py +15 -15
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_runtime/task_lifecycle_manager.py +4 -4
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_traceback.py +14 -2
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_tunnel.py +2 -2
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_utils/function_utils.py +2 -2
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_utils/grpc_utils.py +47 -1
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_utils/task_command_router_client.py +49 -8
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_workspace.py +14 -14
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/app.py +38 -12
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/app.pyi +29 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/cli/app.py +10 -10
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/cli/container.py +5 -5
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/cli/curl.py +1 -1
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/cli/dashboard.py +1 -1
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/cli/endpoint.py +5 -5
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/cli/entry_point.py +0 -3
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/cli/function.py +2 -2
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/cli/image.py +2 -2
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/cli/network_file_system.py +1 -1
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/cli/queues.py +1 -1
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/cli/secret.py +1 -1
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/cli/server.py +2 -2
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/cli/shell.py +27 -10
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/cli/token.py +21 -3
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/cli/utils.py +2 -2
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/client.py +44 -20
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/client.pyi +61 -29
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/cls.py +2 -2
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/config.py +1 -1
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/dict.py +17 -17
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/environments.py +2 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/environments.pyi +53 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/exception.py +4 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/experimental/__init__.py +30 -8
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/experimental/flash.py +5 -5
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/experimental/flash_server.py +1 -1
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/functions.pyi +6 -6
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/io_streams.py +2 -2
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/mount.py +5 -5
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/network_file_system.py +11 -11
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/parallel_map.py +17 -17
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/partial_function.py +2 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/partial_function.pyi +31 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/proxy.py +1 -1
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/queue.py +14 -14
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/runner.py +12 -12
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/sandbox.py +114 -94
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/sandbox.pyi +69 -35
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/secret.py +76 -8
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/secret.pyi +70 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/snapshot.py +1 -1
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/token_flow.py +5 -3
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/token_flow.pyi +15 -3
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/types.py +41 -6
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/volume.py +24 -24
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal.egg-info/PKG-INFO +1 -1
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal.egg-info/SOURCES.txt +2 -3
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal_proto/api_grpc.py +32 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal_proto/api_pb2.py +1439 -1409
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal_proto/api_pb2.pyi +61 -3
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal_proto/api_pb2_grpc.py +66 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal_proto/api_pb2_grpc.pyi +20 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal_proto/modal_api_grpc.py +2 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal_version/__init__.py +1 -1
- modal-1.5.6.dev24/modal/cli/cluster.py +0 -117
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/LICENSE +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/README.md +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/__main__.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_billing.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_clustered_functions.pyi +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_container_entrypoint.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_grpc_client.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_ipython.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_load_context.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_location.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_logs_manager.pyi +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_object.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_output/__init__.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_output/manager.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_output/rich.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_output/status.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_resolver.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_resources.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_runtime/__init__.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_runtime/asgi.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_runtime/container_io_manager.pyi +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_runtime/execution_context.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_runtime/execution_context.pyi +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_runtime/gpu_memory_snapshot.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_runtime/task_lifecycle_manager.pyi +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_runtime/telemetry.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_runtime/user_code_event_loop.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_runtime/user_code_imports.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_serialization.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_server.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_supports_logs.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_tunnel.pyi +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_type_manager.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_utils/__init__.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_utils/app_utils.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_utils/async_utils.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_utils/auth_token_manager.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_utils/blob_utils.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_utils/browser_utils.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_utils/bytes_io_segment_payload.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_utils/curl_utils.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_utils/deprecation.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_utils/display_utils.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_utils/docker_utils.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_utils/git_utils.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_utils/grpc_testing.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_utils/hash_utils.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_utils/http_utils.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_utils/idle_countdown.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_utils/jwt_utils.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_utils/logger.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_utils/mount_utils.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_utils/name_utils.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_utils/package_utils.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_utils/pattern_utils.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_utils/proxy_support.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_utils/rand_pb_testing.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_utils/sandbox_fs_utils.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_utils/shell_utils.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_utils/time_utils.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_vendor/__init__.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_vendor/a2wsgi_wsgi.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_vendor/cloudpickle.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_vendor/tblib.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_vendor/version.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/_watcher.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/billing.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/billing.pyi +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/builder/2023.12.312.txt +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/builder/2023.12.txt +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/builder/2024.04.txt +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/builder/2024.10.txt +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/builder/2025.06.txt +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/builder/PREVIEW.txt +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/builder/README.md +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/builder/base-images.json +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/call_graph.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/cli/__init__.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/cli/_download.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/cli/_help.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/cli/_logs.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/cli/_stats.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/cli/_traceback.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/cli/billing.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/cli/changelog.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/cli/config.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/cli/dict.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/cli/environment.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/cli/import_refs.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/cli/logo.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/cli/profile.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/cli/run.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/cli/selector.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/cli/skills.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/cli/volume.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/cli/workspace.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/cloud_bucket_mount.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/cloud_bucket_mount.pyi +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/cls.pyi +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/container_process.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/container_process.pyi +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/dict.pyi +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/experimental/_flash_container_entry.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/experimental/flash.pyi +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/experimental/flash_server.pyi +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/experimental/ipython.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/file_pattern_matcher.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/functions.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/image.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/image.pyi +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/io_streams.pyi +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/mount.pyi +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/network_file_system.pyi +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/object.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/object.pyi +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/output.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/parallel_map.pyi +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/proxy.pyi +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/py.typed +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/queue.pyi +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/retries.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/runner.pyi +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/running_app.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/sandbox_fs.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/sandbox_fs.pyi +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/schedule.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/scheduler_placement.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/server.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/server.pyi +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/serving.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/serving.pyi +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/skills/modal/SKILL.md +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/snapshot.pyi +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/stream_type.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/volume.pyi +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/workspace.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal/workspace.pyi +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal.egg-info/dependency_links.txt +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal.egg-info/entry_points.txt +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal.egg-info/requires.txt +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal.egg-info/top_level.txt +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal_docs/__init__.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal_docs/gen_cli_docs.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal_docs/gen_cli_docs_main.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal_docs/gen_reference_docs.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal_docs/gen_reference_docs_main.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal_docs/mdmd/__init__.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal_docs/mdmd/mdmd.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal_docs/mdmd/signatures.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal_docs/mdmd/types.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal_docs/reference_intro.md +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal_proto/__init__.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal_proto/py.typed +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal_proto/task_command_router_grpc.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal_proto/task_command_router_pb2.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal_proto/task_command_router_pb2.pyi +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal_proto/task_command_router_pb2_grpc.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal_proto/task_command_router_pb2_grpc.pyi +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/modal_version/__main__.py +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/pyproject.toml +0 -0
- {modal-1.5.6.dev24 → modal-1.5.6.dev26}/setup.cfg +0 -0
|
@@ -9,7 +9,7 @@ if sys.version_info[:2] >= (3, 15):
|
|
|
9
9
|
from modal_version import __version__
|
|
10
10
|
|
|
11
11
|
try:
|
|
12
|
-
from . import billing, types
|
|
12
|
+
from . import billing, experimental, types
|
|
13
13
|
from ._runtime.execution_context import current_function_call_id, current_input_id, interact, is_local
|
|
14
14
|
from ._tunnel import Tunnel, forward
|
|
15
15
|
from .app import App
|
|
@@ -23,11 +23,11 @@ try:
|
|
|
23
23
|
from .functions import Function, FunctionCall
|
|
24
24
|
from .image import Image
|
|
25
25
|
from .network_file_system import NetworkFileSystem
|
|
26
|
-
from .outbound_policy import OutboundPolicy
|
|
27
26
|
from .output import enable_output
|
|
28
27
|
from .partial_function import (
|
|
29
28
|
asgi_app,
|
|
30
29
|
batched,
|
|
30
|
+
clustered,
|
|
31
31
|
concurrent,
|
|
32
32
|
enter,
|
|
33
33
|
exit,
|
|
@@ -72,7 +72,6 @@ __all__ = [
|
|
|
72
72
|
"FunctionCall",
|
|
73
73
|
"Image",
|
|
74
74
|
"NetworkFileSystem",
|
|
75
|
-
"OutboundPolicy",
|
|
76
75
|
"Period",
|
|
77
76
|
"Probe",
|
|
78
77
|
"Proxy",
|
|
@@ -90,12 +89,14 @@ __all__ = [
|
|
|
90
89
|
"asgi_app",
|
|
91
90
|
"batched",
|
|
92
91
|
"billing",
|
|
92
|
+
"clustered",
|
|
93
93
|
"concurrent",
|
|
94
94
|
"current_function_call_id",
|
|
95
95
|
"current_input_id",
|
|
96
96
|
"enable_output",
|
|
97
97
|
"enter",
|
|
98
98
|
"exit",
|
|
99
|
+
"experimental",
|
|
99
100
|
"fastapi_endpoint",
|
|
100
101
|
"forward",
|
|
101
102
|
"is_local",
|
|
@@ -71,7 +71,7 @@ async def _initialize_clustered_function(client: _Client, task_id: str, world_si
|
|
|
71
71
|
os.environ["NCCL_NSOCKS_PERTHREAD"] = "1"
|
|
72
72
|
|
|
73
73
|
if world_size > 1:
|
|
74
|
-
resp = await client.
|
|
74
|
+
resp = await client._stub.TaskClusterHello(
|
|
75
75
|
api_pb2.TaskClusterHelloRequest(
|
|
76
76
|
task_id=task_id,
|
|
77
77
|
container_ip=container_ip,
|
|
@@ -4,7 +4,7 @@ import builtins
|
|
|
4
4
|
from collections.abc import Iterable, Mapping
|
|
5
5
|
from dataclasses import dataclass
|
|
6
6
|
from datetime import datetime, timezone
|
|
7
|
-
from typing import Any, Literal
|
|
7
|
+
from typing import TYPE_CHECKING, Any, Literal
|
|
8
8
|
|
|
9
9
|
from google.protobuf.empty_pb2 import Empty
|
|
10
10
|
from google.protobuf.message import Message
|
|
@@ -24,6 +24,9 @@ from .config import config, logger
|
|
|
24
24
|
from .exception import InvalidError, WorkspaceManagementError
|
|
25
25
|
from .types import BillingReportItem, EnvironmentBillingSummary
|
|
26
26
|
|
|
27
|
+
if TYPE_CHECKING:
|
|
28
|
+
import modal
|
|
29
|
+
|
|
27
30
|
|
|
28
31
|
@dataclass(frozen=True)
|
|
29
32
|
class EnvironmentSettings:
|
|
@@ -59,7 +62,7 @@ class _EnvironmentManager:
|
|
|
59
62
|
request.default_member_role_str = default_role
|
|
60
63
|
if (experimental_options or {}).get("is_public", False):
|
|
61
64
|
request.environment_type = api_pb2.ENVIRONMENT_TYPE_PUBLIC
|
|
62
|
-
await client.
|
|
65
|
+
await client._stub.EnvironmentCreate(request)
|
|
63
66
|
|
|
64
67
|
async def list(
|
|
65
68
|
self,
|
|
@@ -76,7 +79,7 @@ class _EnvironmentManager:
|
|
|
76
79
|
```
|
|
77
80
|
"""
|
|
78
81
|
client = await _Client.from_env() if client is None else client
|
|
79
|
-
resp = await client.
|
|
82
|
+
resp = await client._stub.EnvironmentList(Empty())
|
|
80
83
|
environments = []
|
|
81
84
|
for item in resp.items:
|
|
82
85
|
metadata = api_pb2.EnvironmentMetadata(
|
|
@@ -110,7 +113,7 @@ class _EnvironmentManager:
|
|
|
110
113
|
```
|
|
111
114
|
"""
|
|
112
115
|
client = await _Client.from_env() if client is None else client
|
|
113
|
-
await client.
|
|
116
|
+
await client._stub.EnvironmentDelete(api_pb2.EnvironmentDeleteRequest(name=name))
|
|
114
117
|
|
|
115
118
|
|
|
116
119
|
class _EnvironmentRolesManager:
|
|
@@ -139,7 +142,7 @@ class _EnvironmentRolesManager:
|
|
|
139
142
|
"""
|
|
140
143
|
await self._environment.hydrate()
|
|
141
144
|
req = api_pb2.EnvironmentGetRolesRequest(environment_id=self._environment.object_id)
|
|
142
|
-
resp = await self._environment.client.
|
|
145
|
+
resp = await self._environment.client._stub.EnvironmentGetRoles(req)
|
|
143
146
|
|
|
144
147
|
users: dict[str, str] = {}
|
|
145
148
|
service_users: dict[str, str] = {}
|
|
@@ -180,7 +183,7 @@ class _EnvironmentRolesManager:
|
|
|
180
183
|
service_users = service_users or {}
|
|
181
184
|
|
|
182
185
|
req = api_pb2.EnvironmentGetRolesRequest(environment_id=self._environment.object_id)
|
|
183
|
-
resp = await self._environment.client.
|
|
186
|
+
resp = await self._environment.client._stub.EnvironmentGetRoles(req)
|
|
184
187
|
|
|
185
188
|
# EnvironmentGetRoles returns every workspace principal
|
|
186
189
|
user_name_to_id: dict[str, str] = {}
|
|
@@ -214,7 +217,7 @@ class _EnvironmentRolesManager:
|
|
|
214
217
|
async def _dispatch_role_updates(self, requests: dict[str, api_pb2.EnvironmentRoleSetRequest]) -> None:
|
|
215
218
|
"""Send batched EnvironmentRoleSet RPCs and report all errors encountered."""
|
|
216
219
|
results = await asyncio.gather(
|
|
217
|
-
*(self._environment.client.
|
|
220
|
+
*(self._environment.client._stub.EnvironmentRoleSet(req) for req in requests.values()),
|
|
218
221
|
return_exceptions=True,
|
|
219
222
|
)
|
|
220
223
|
errors = [(label, result) for label, result in zip(requests.keys(), results) if isinstance(result, Exception)]
|
|
@@ -269,7 +272,7 @@ class _EnvironmentMembersManager:
|
|
|
269
272
|
service_users = service_users or []
|
|
270
273
|
|
|
271
274
|
req = api_pb2.EnvironmentGetRolesRequest(environment_id=self._environment.object_id)
|
|
272
|
-
resp = await self._environment.client.
|
|
275
|
+
resp = await self._environment.client._stub.EnvironmentGetRoles(req)
|
|
273
276
|
|
|
274
277
|
user_name_to_id: dict[str, str] = {}
|
|
275
278
|
service_user_name_to_id: dict[str, str] = {}
|
|
@@ -300,6 +303,55 @@ class _EnvironmentMembersManager:
|
|
|
300
303
|
await _EnvironmentRolesManager(self._environment)._dispatch_role_updates(requests)
|
|
301
304
|
|
|
302
305
|
|
|
306
|
+
class _EnvironmentAppsManager:
|
|
307
|
+
"""mdmd:namespace"""
|
|
308
|
+
|
|
309
|
+
def __init__(self, environment: "_Environment"):
|
|
310
|
+
"""mdmd:hidden"""
|
|
311
|
+
self._environment = environment
|
|
312
|
+
|
|
313
|
+
async def list(self) -> builtins.list["modal.app._App"]:
|
|
314
|
+
"""Return handles for live Apps in this Environment.
|
|
315
|
+
|
|
316
|
+
The returned handles reference existing remote Apps and can be used with APIs such as
|
|
317
|
+
[`App.info()`](https://modal.com/docs/sdk/py/latest/App#info),
|
|
318
|
+
[`App.logs`](https://modal.com/docs/sdk/py/latest/App#logs), and
|
|
319
|
+
[`Sandbox.create()`](https://modal.com/docs/sdk/py/latest/Sandbox#create). Listing Apps does not create
|
|
320
|
+
Apps.
|
|
321
|
+
|
|
322
|
+
Examples:
|
|
323
|
+
|
|
324
|
+
```python notest
|
|
325
|
+
environment = modal.Environment.from_name("prod")
|
|
326
|
+
apps = environment.apps.list()
|
|
327
|
+
print([app.name for app in apps])
|
|
328
|
+
```
|
|
329
|
+
"""
|
|
330
|
+
from .app import _App
|
|
331
|
+
|
|
332
|
+
await self._environment.hydrate()
|
|
333
|
+
assert self._environment.name is not None
|
|
334
|
+
|
|
335
|
+
response = await self._environment.client._stub.AppList(
|
|
336
|
+
api_pb2.AppListRequest(environment_name=self._environment.name)
|
|
337
|
+
)
|
|
338
|
+
stopped_app_states = (
|
|
339
|
+
api_pb2.APP_STATE_STOPPED,
|
|
340
|
+
api_pb2.APP_STATE_DISABLED,
|
|
341
|
+
)
|
|
342
|
+
return [
|
|
343
|
+
_App._new_remote(
|
|
344
|
+
item.name or None,
|
|
345
|
+
item.app_id,
|
|
346
|
+
self._environment.name,
|
|
347
|
+
self._environment.client,
|
|
348
|
+
description=item.description or None,
|
|
349
|
+
)
|
|
350
|
+
for item in response.apps
|
|
351
|
+
if item.state not in stopped_app_states
|
|
352
|
+
]
|
|
353
|
+
|
|
354
|
+
|
|
303
355
|
class _Environment(_Object, type_prefix="en"):
|
|
304
356
|
_name: str | None = None
|
|
305
357
|
_settings: EnvironmentSettings
|
|
@@ -334,6 +386,11 @@ class _Environment(_Object, type_prefix="en"):
|
|
|
334
386
|
# Deprecated alias for `Environment.roles`.
|
|
335
387
|
return _EnvironmentMembersManager(self)
|
|
336
388
|
|
|
389
|
+
@property
|
|
390
|
+
def apps(self) -> "_EnvironmentAppsManager":
|
|
391
|
+
"""Namespace for accessing Apps deployed in this Environment."""
|
|
392
|
+
return _EnvironmentAppsManager(self)
|
|
393
|
+
|
|
337
394
|
# TODO(michael) Keeping this private for now until we decide what else should be in it
|
|
338
395
|
# And what the rules should be about updates / mutability
|
|
339
396
|
# @property
|
|
@@ -366,7 +423,7 @@ class _Environment(_Object, type_prefix="en"):
|
|
|
366
423
|
else api_pb2.OBJECT_CREATION_TYPE_UNSPECIFIED
|
|
367
424
|
),
|
|
368
425
|
)
|
|
369
|
-
response = await load_context.client.
|
|
426
|
+
response = await load_context.client._stub.EnvironmentGetOrCreate(request)
|
|
370
427
|
logger.debug(f"Created environment with id {response.environment_id}")
|
|
371
428
|
self._hydrate(response.environment_id, load_context.client, response.metadata)
|
|
372
429
|
|
|
@@ -491,7 +548,7 @@ class _EnvironmentBillingManager:
|
|
|
491
548
|
|
|
492
549
|
return [
|
|
493
550
|
BillingReportItem._from_proto(pb_item)
|
|
494
|
-
async for pb_item in self._environment.client.
|
|
551
|
+
async for pb_item in self._environment.client._stub.WorkspaceBillingReport.unary_stream(request)
|
|
495
552
|
]
|
|
496
553
|
|
|
497
554
|
async def summary(
|
|
@@ -556,7 +613,7 @@ class _EnvironmentBillingManager:
|
|
|
556
613
|
request.start_timestamp.FromDatetime(cycle)
|
|
557
614
|
|
|
558
615
|
return EnvironmentBillingSummary._from_proto(
|
|
559
|
-
await self._environment.client.
|
|
616
|
+
await self._environment.client._stub.EnvironmentBillingSummary(request)
|
|
560
617
|
)
|
|
561
618
|
|
|
562
619
|
|
|
@@ -582,7 +639,7 @@ async def _get_environment_cached(name: str, client: _Client) -> _Environment:
|
|
|
582
639
|
async def _delete_environment(name: str, client: _Client | None = None):
|
|
583
640
|
if client is None:
|
|
584
641
|
client = await _Client.from_env()
|
|
585
|
-
await client.
|
|
642
|
+
await client._stub.EnvironmentDelete(api_pb2.EnvironmentDeleteRequest(name=name))
|
|
586
643
|
|
|
587
644
|
|
|
588
645
|
async def _update_environment(
|
|
@@ -608,19 +665,19 @@ async def _update_environment(
|
|
|
608
665
|
)
|
|
609
666
|
if client is None:
|
|
610
667
|
client = await _Client.from_env()
|
|
611
|
-
await client.
|
|
668
|
+
await client._stub.EnvironmentUpdate(update_payload)
|
|
612
669
|
|
|
613
670
|
|
|
614
671
|
async def _create_environment(name: str, client: _Client | None = None):
|
|
615
672
|
if client is None:
|
|
616
673
|
client = await _Client.from_env()
|
|
617
|
-
await client.
|
|
674
|
+
await client._stub.EnvironmentCreate(api_pb2.EnvironmentCreateRequest(name=name))
|
|
618
675
|
|
|
619
676
|
|
|
620
677
|
async def _list_environments(client: _Client | None = None) -> list[api_pb2.EnvironmentListItem]:
|
|
621
678
|
if client is None:
|
|
622
679
|
client = await _Client.from_env()
|
|
623
|
-
resp = await client.
|
|
680
|
+
resp = await client._stub.EnvironmentList(Empty())
|
|
624
681
|
return list(resp.items)
|
|
625
682
|
|
|
626
683
|
|
|
@@ -335,7 +335,7 @@ async def _list_function_variants(
|
|
|
335
335
|
cursor = None
|
|
336
336
|
while True:
|
|
337
337
|
request = api_pb2.FunctionListVariantsRequest(function_id=function_id, cursor=cursor, limit=limit or 0)
|
|
338
|
-
response = await client.
|
|
338
|
+
response = await client._stub.FunctionListVariants(request)
|
|
339
339
|
# An ordered listing arrives as a single response, so there is nothing to reconcile across
|
|
340
340
|
# pages: every response of a multi-page listing reports itself unordered.
|
|
341
341
|
ordered_by_task_count = response.ordered_by_task_count
|
|
@@ -376,8 +376,8 @@ async def _function_bind_params_cached(
|
|
|
376
376
|
response.ParseFromString(cached_response)
|
|
377
377
|
return response
|
|
378
378
|
|
|
379
|
-
assert base_function._client and base_function._client.
|
|
380
|
-
response = await base_function._client.
|
|
379
|
+
assert base_function._client and base_function._client._stub
|
|
380
|
+
response = await base_function._client._stub.FunctionBindParams(req)
|
|
381
381
|
|
|
382
382
|
cache[cache_key] = response.SerializeToString(deterministic=True)
|
|
383
383
|
cache.move_to_end(cache_key)
|
|
@@ -407,7 +407,7 @@ def _make_function_variant(
|
|
|
407
407
|
if not base_function._is_hydrated:
|
|
408
408
|
await base_function.hydrate(load_context.client)
|
|
409
409
|
|
|
410
|
-
assert base_function._client and base_function._client.
|
|
410
|
+
assert base_function._client and base_function._client._stub
|
|
411
411
|
|
|
412
412
|
if parameter_schema is None:
|
|
413
413
|
# This branch is about backwards compatibility.
|
|
@@ -158,8 +158,8 @@ class _Invocation:
|
|
|
158
158
|
function_call_invocation_type: "api_pb2.FunctionCallInvocationType.ValueType",
|
|
159
159
|
from_spawn_map: bool = False,
|
|
160
160
|
) -> "_Invocation":
|
|
161
|
-
assert client.
|
|
162
|
-
stub = client.
|
|
161
|
+
assert client._stub
|
|
162
|
+
stub = client._stub
|
|
163
163
|
|
|
164
164
|
function_id = function.object_id
|
|
165
165
|
item = await _create_input(
|
|
@@ -180,7 +180,7 @@ class _Invocation:
|
|
|
180
180
|
|
|
181
181
|
if from_spawn_map:
|
|
182
182
|
request.from_spawn_map = True
|
|
183
|
-
response = await client.
|
|
183
|
+
response = await client._stub.FunctionMap(
|
|
184
184
|
request,
|
|
185
185
|
retry=Retry(
|
|
186
186
|
max_retries=None,
|
|
@@ -195,7 +195,7 @@ class _Invocation:
|
|
|
195
195
|
),
|
|
196
196
|
)
|
|
197
197
|
else:
|
|
198
|
-
response = await client.
|
|
198
|
+
response = await client._stub.FunctionMap(request)
|
|
199
199
|
|
|
200
200
|
function_call_id = response.function_call_id
|
|
201
201
|
if response.pipelined_inputs:
|
|
@@ -215,7 +215,7 @@ class _Invocation:
|
|
|
215
215
|
request_put = api_pb2.FunctionPutInputsRequest(
|
|
216
216
|
function_id=function_id, inputs=[item], function_call_id=function_call_id
|
|
217
217
|
)
|
|
218
|
-
inputs_response: api_pb2.FunctionPutInputsResponse = await client.
|
|
218
|
+
inputs_response: api_pb2.FunctionPutInputsResponse = await client._stub.FunctionPutInputs(request_put)
|
|
219
219
|
processed_inputs = inputs_response.inputs
|
|
220
220
|
if not processed_inputs:
|
|
221
221
|
raise Exception("Could not create function call - the input queue seems to be full")
|
|
@@ -438,10 +438,10 @@ class _InputPlaneInvocation:
|
|
|
438
438
|
input_plane_region: str,
|
|
439
439
|
function_call_invocation_type: "api_pb2.FunctionCallInvocationType.ValueType",
|
|
440
440
|
) -> "_InputPlaneInvocation":
|
|
441
|
-
stub = await client.
|
|
441
|
+
stub = await client._get_stub(input_plane_url)
|
|
442
442
|
|
|
443
443
|
function_id = function.object_id
|
|
444
|
-
control_plane_stub = client.
|
|
444
|
+
control_plane_stub = client._stub
|
|
445
445
|
# Note: Blob upload is done on the control plane stub, not the input plane stub!
|
|
446
446
|
input_item = await _create_input(
|
|
447
447
|
args,
|
|
@@ -491,7 +491,7 @@ class _InputPlaneInvocation:
|
|
|
491
491
|
# If we have a final output, return.
|
|
492
492
|
if await_response.output.result.status in TERMINAL_STATUSES:
|
|
493
493
|
return await _process_result(
|
|
494
|
-
await_response.output.result, await_response.output.data_format, self.client.
|
|
494
|
+
await_response.output.result, await_response.output.data_format, self.client._stub, self.client
|
|
495
495
|
)
|
|
496
496
|
|
|
497
497
|
# We have a failure (internal or application), so see if there are any retries left, and if so, retry.
|
|
@@ -510,7 +510,7 @@ class _InputPlaneInvocation:
|
|
|
510
510
|
|
|
511
511
|
# No more retries left.
|
|
512
512
|
return await _process_result(
|
|
513
|
-
await_response.output.result, await_response.output.data_format, self.client.
|
|
513
|
+
await_response.output.result, await_response.output.data_format, self.client._stub, self.client
|
|
514
514
|
)
|
|
515
515
|
|
|
516
516
|
async def _retry_input(self, metadata: list[tuple[str, str]]) -> str:
|
|
@@ -731,6 +731,25 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
|
|
|
731
731
|
# Needed to avoid circular imports
|
|
732
732
|
from ._partial_function import _find_partial_methods_for_user_cls, _PartialFunctionFlags
|
|
733
733
|
|
|
734
|
+
experimental_options = dict(experimental_options or {})
|
|
735
|
+
if "fabric_size" in experimental_options:
|
|
736
|
+
if fabric_size is not None:
|
|
737
|
+
raise InvalidError(
|
|
738
|
+
"Specify fabric_size only once, in experimental_options or the experimental decorator"
|
|
739
|
+
)
|
|
740
|
+
try:
|
|
741
|
+
fabric_size = int(experimental_options.pop("fabric_size"))
|
|
742
|
+
except ValueError:
|
|
743
|
+
raise InvalidError("fabric_size must be a positive integer") from None
|
|
744
|
+
if fabric_size <= 0:
|
|
745
|
+
raise InvalidError("fabric_size must be a positive integer")
|
|
746
|
+
if not cluster_size:
|
|
747
|
+
raise InvalidError("fabric_size requires @modal.clustered")
|
|
748
|
+
if cluster_size % fabric_size != 0:
|
|
749
|
+
raise InvalidError(
|
|
750
|
+
f"fabric_size must evenly divide the cluster size ({cluster_size} % {fabric_size} != 0)"
|
|
751
|
+
)
|
|
752
|
+
|
|
734
753
|
tag = info.get_tag()
|
|
735
754
|
|
|
736
755
|
if info.raw_f:
|
|
@@ -818,6 +837,9 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
|
|
|
818
837
|
validate_target_concurrency(target_concurrent_inputs, "target_inputs", allow_fractional=False)
|
|
819
838
|
target_concurrent_inputs_int = int(target_concurrent_inputs)
|
|
820
839
|
|
|
840
|
+
if cluster_size and batch_max_size:
|
|
841
|
+
raise InvalidError("Clustered Functions do not support dynamic batching.")
|
|
842
|
+
|
|
821
843
|
# For clustered functions, container settings must be multiples of cluster_size
|
|
822
844
|
if cluster_size is not None and cluster_size > 1:
|
|
823
845
|
for field in ["min_containers", "max_containers", "buffer_containers"]:
|
|
@@ -941,7 +963,7 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
|
|
|
941
963
|
elif webhook_config:
|
|
942
964
|
req.webhook_config.CopyFrom(webhook_config)
|
|
943
965
|
|
|
944
|
-
response = await load_context.client.
|
|
966
|
+
response = await load_context.client._stub.FunctionPrecreate(req)
|
|
945
967
|
self._hydrate(response.function_id, load_context.client, response.handle_metadata)
|
|
946
968
|
|
|
947
969
|
async def _load(self: _Function, resolver: Resolver, load_context: LoadContext, existing_object_id: str | None):
|
|
@@ -1155,7 +1177,7 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
|
|
|
1155
1177
|
existing_function_id=existing_object_id or "",
|
|
1156
1178
|
)
|
|
1157
1179
|
try:
|
|
1158
|
-
response: api_pb2.FunctionCreateResponse = await load_context.client.
|
|
1180
|
+
response: api_pb2.FunctionCreateResponse = await load_context.client._stub.FunctionCreate(request)
|
|
1159
1181
|
except Exception as exc:
|
|
1160
1182
|
if "Received :status = '413'" in str(exc):
|
|
1161
1183
|
raise InvalidError(f"Function {info.function_name} is too large to deploy.")
|
|
@@ -1230,7 +1252,8 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
|
|
|
1230
1252
|
},
|
|
1231
1253
|
# We don't have any secret IDs yet as we are dehydrated, so we return the reprs instead
|
|
1232
1254
|
secrets=[repr(s) for s in secrets],
|
|
1233
|
-
|
|
1255
|
+
_http_info=HttpInfo._from_proto(http_config) if http_config else None,
|
|
1256
|
+
web_info=FunctionInfo.WebInfo._from_proto(webhook_config) if webhook_config else None,
|
|
1234
1257
|
)
|
|
1235
1258
|
|
|
1236
1259
|
return obj
|
|
@@ -1256,7 +1279,7 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
|
|
|
1256
1279
|
scaledown_window=scaledown_window,
|
|
1257
1280
|
)
|
|
1258
1281
|
request = api_pb2.FunctionUpdateSchedulingParamsRequest(function_id=self.object_id, settings=settings)
|
|
1259
|
-
response = await self.client.
|
|
1282
|
+
response = await self.client._stub.FunctionUpdateSchedulingParams(request)
|
|
1260
1283
|
|
|
1261
1284
|
return FunctionAutoscalerSettings._from_proto(response.current_settings)
|
|
1262
1285
|
|
|
@@ -1281,7 +1304,7 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
|
|
|
1281
1304
|
validate_target_concurrency(target_concurrency, "target_concurrency", allow_fractional=True)
|
|
1282
1305
|
settings.target_concurrency_float = normalize_fractional_target_concurrency(target_concurrency)
|
|
1283
1306
|
request = api_pb2.FunctionUpdateSchedulingParamsRequest(function_id=self.object_id, settings=settings)
|
|
1284
|
-
response = await self.client.
|
|
1307
|
+
response = await self.client._stub.FunctionUpdateSchedulingParams(request)
|
|
1285
1308
|
|
|
1286
1309
|
return ServerAutoscalerSettings._from_proto(response.current_settings)
|
|
1287
1310
|
|
|
@@ -1359,7 +1382,7 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
|
|
|
1359
1382
|
app_version=version or 0,
|
|
1360
1383
|
)
|
|
1361
1384
|
try:
|
|
1362
|
-
response = await load_context.client.
|
|
1385
|
+
response = await load_context.client._stub.FunctionGet(request)
|
|
1363
1386
|
except NotFoundError as exc:
|
|
1364
1387
|
# refine the error message
|
|
1365
1388
|
env_context = (
|
|
@@ -1403,7 +1426,7 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
|
|
|
1403
1426
|
):
|
|
1404
1427
|
request = api_pb2.FunctionGetByIdRequest(function_id=function_id)
|
|
1405
1428
|
try:
|
|
1406
|
-
response = await load_context.client.
|
|
1429
|
+
response = await load_context.client._stub.FunctionGetById(request)
|
|
1407
1430
|
except NotFoundError as exc:
|
|
1408
1431
|
# refine the error message
|
|
1409
1432
|
msg = f"Lookup failed for {called_from} '{function_id}': {exc}."
|
|
@@ -1563,7 +1586,7 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
|
|
|
1563
1586
|
if refresh or self._function_info is None:
|
|
1564
1587
|
# Accessing `.client` or `.object_id` here can't throw since we only get to this branch on a
|
|
1565
1588
|
# hydrated handle
|
|
1566
|
-
response = await self.client.
|
|
1589
|
+
response = await self.client._stub.FunctionGetById(
|
|
1567
1590
|
api_pb2.FunctionGetByIdRequest(
|
|
1568
1591
|
function_id=self.object_id,
|
|
1569
1592
|
)
|
|
@@ -2224,7 +2247,7 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
|
|
|
2224
2247
|
Returns:
|
|
2225
2248
|
A `FunctionCurrentStats` object containing live input and container counts.
|
|
2226
2249
|
"""
|
|
2227
|
-
resp = await self.client.
|
|
2250
|
+
resp = await self.client._stub.FunctionGetCurrentStats(
|
|
2228
2251
|
api_pb2.FunctionGetCurrentStatsRequest(function_id=self.object_id),
|
|
2229
2252
|
retry=Retry(total_timeout=10.0),
|
|
2230
2253
|
)
|
|
@@ -2270,7 +2293,7 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
|
|
|
2270
2293
|
historical_request.until.FromDatetime(until)
|
|
2271
2294
|
if container:
|
|
2272
2295
|
historical_request.container_id = container
|
|
2273
|
-
stats = await self.client.
|
|
2296
|
+
stats = await self.client._stub.FunctionGetTimeRangeStats(historical_request)
|
|
2274
2297
|
return FunctionStats._from_proto(stats)
|
|
2275
2298
|
|
|
2276
2299
|
@live_method
|
|
@@ -2307,12 +2330,12 @@ class _FunctionCall(typing.Generic[ReturnType], _Object, type_prefix="fc"):
|
|
|
2307
2330
|
_function_id: str | None = None
|
|
2308
2331
|
|
|
2309
2332
|
def _invocation(self):
|
|
2310
|
-
return _Invocation(self.client.
|
|
2333
|
+
return _Invocation(self.client._stub, self.object_id, self.client)
|
|
2311
2334
|
|
|
2312
2335
|
async def _hydrate_from_id_metadata(self) -> None:
|
|
2313
2336
|
"""Hydrate metadata only when needed for FunctionCall fields."""
|
|
2314
2337
|
request = api_pb2.FunctionCallFromIdRequest(function_call_id=self.object_id)
|
|
2315
|
-
resp = await self.client.
|
|
2338
|
+
resp = await self.client._stub.FunctionCallFromId(request)
|
|
2316
2339
|
self._hydrate_metadata(resp)
|
|
2317
2340
|
|
|
2318
2341
|
async def _get_log_query_data(self) -> _LogQueryData:
|
|
@@ -2428,9 +2451,9 @@ class _FunctionCall(typing.Generic[ReturnType], _Object, type_prefix="fc"):
|
|
|
2428
2451
|
Returns:
|
|
2429
2452
|
A list of `InputInfo` nodes describing the call graph.
|
|
2430
2453
|
"""
|
|
2431
|
-
assert self._client and self._client.
|
|
2454
|
+
assert self._client and self._client._stub
|
|
2432
2455
|
request = api_pb2.FunctionGetCallGraphRequest(function_call_id=self.object_id)
|
|
2433
|
-
response = await self._client.
|
|
2456
|
+
response = await self._client._stub.FunctionGetCallGraph(request)
|
|
2434
2457
|
if response.truncated:
|
|
2435
2458
|
logger.warning(
|
|
2436
2459
|
f"Call graph for {self.object_id} was truncated; "
|
|
@@ -2450,8 +2473,8 @@ class _FunctionCall(typing.Generic[ReturnType], _Object, type_prefix="fc"):
|
|
|
2450
2473
|
request = api_pb2.FunctionCallCancelRequest(
|
|
2451
2474
|
function_call_id=self.object_id, terminate_containers=terminate_containers
|
|
2452
2475
|
)
|
|
2453
|
-
assert self._client and self._client.
|
|
2454
|
-
await self._client.
|
|
2476
|
+
assert self._client and self._client._stub
|
|
2477
|
+
await self._client._stub.FunctionCallCancel(request)
|
|
2455
2478
|
|
|
2456
2479
|
@deprecate_aio_usage((2025, 11, 14), "FunctionCall.from_id")
|
|
2457
2480
|
@classmethod
|
|
@@ -438,7 +438,7 @@ async def _image_await_build_result(image_id: str, client: _Client) -> api_pb2.I
|
|
|
438
438
|
nonlocal last_entry_id, result_response
|
|
439
439
|
|
|
440
440
|
request = api_pb2.ImageJoinStreamingRequest(image_id=image_id, timeout=55, last_entry_id=last_entry_id)
|
|
441
|
-
async for response in client.
|
|
441
|
+
async for response in client._stub.ImageJoinStreaming.unary_stream(request):
|
|
442
442
|
if response.entry_id:
|
|
443
443
|
last_entry_id = response.entry_id
|
|
444
444
|
if response.result.status:
|
|
@@ -746,7 +746,7 @@ class _Image(_Object, type_prefix="im"):
|
|
|
746
746
|
allow_global_deployment=os.environ.get("MODAL_IMAGE_ALLOW_GLOBAL_DEPLOYMENT") == "1",
|
|
747
747
|
ignore_cache=config.get("ignore_cache"),
|
|
748
748
|
)
|
|
749
|
-
resp = await load_context.client.
|
|
749
|
+
resp = await load_context.client._stub.ImageGetOrCreate(req)
|
|
750
750
|
image_id = resp.image_id
|
|
751
751
|
result: api_pb2.GenericResult
|
|
752
752
|
metadata: api_pb2.ImageMetadata | None = None
|
|
@@ -1013,7 +1013,7 @@ class _Image(_Object, type_prefix="im"):
|
|
|
1013
1013
|
_client = typing.cast(_Client, synchronizer._translate_in(client))
|
|
1014
1014
|
|
|
1015
1015
|
async def _load(self: _Image, resolver: Resolver, load_context: LoadContext, existing_object_id: str | None):
|
|
1016
|
-
resp = await load_context.client.
|
|
1016
|
+
resp = await load_context.client._stub.ImageFromId(api_pb2.ImageFromIdRequest(image_id=image_id))
|
|
1017
1017
|
self._hydrate(resp.image_id, load_context.client, resp.metadata)
|
|
1018
1018
|
|
|
1019
1019
|
rep = f"Image.from_id({image_id!r})"
|
|
@@ -2959,7 +2959,7 @@ class _Image(_Object, type_prefix="im"):
|
|
|
2959
2959
|
request = api_pb2.ImageJoinStreamingRequest(
|
|
2960
2960
|
image_id=self.object_id, timeout=55, last_entry_id=last_entry_id, include_logs_for_finished=True
|
|
2961
2961
|
)
|
|
2962
|
-
async for response in self.client.
|
|
2962
|
+
async for response in self.client._stub.ImageJoinStreaming.unary_stream(request):
|
|
2963
2963
|
if response.result.status:
|
|
2964
2964
|
return
|
|
2965
2965
|
if response.entry_id:
|
|
@@ -2995,7 +2995,7 @@ class _Image(_Object, type_prefix="im"):
|
|
|
2995
2995
|
req = api_pb2.ImageGetByTagRequest(
|
|
2996
2996
|
tag=_upgrade_image_name(name, fallback_environment_name=load_context.environment_name),
|
|
2997
2997
|
)
|
|
2998
|
-
response = await load_context.client.
|
|
2998
|
+
response = await load_context.client._stub.ImageGetByTag(req)
|
|
2999
2999
|
self._hydrate(response.image_id, load_context.client, None)
|
|
3000
3000
|
|
|
3001
3001
|
rep = _Image._repr(name, environment_name)
|
|
@@ -3039,7 +3039,7 @@ class _Image(_Object, type_prefix="im"):
|
|
|
3039
3039
|
fallback_environment_name=config.get("environment"),
|
|
3040
3040
|
)
|
|
3041
3041
|
|
|
3042
|
-
await _client.
|
|
3042
|
+
await _client._stub.ImagePublish(
|
|
3043
3043
|
api_pb2.ImagePublishRequest(
|
|
3044
3044
|
image_id=self._object_id,
|
|
3045
3045
|
allow_public=bool((experimental_options or {}).get("is_public", False)),
|
|
@@ -3074,7 +3074,7 @@ class _Image(_Object, type_prefix="im"):
|
|
|
3074
3074
|
|
|
3075
3075
|
if self._build_steps is None:
|
|
3076
3076
|
request = api_pb2.ImageBuildChainGetRequest(image_id=image_id)
|
|
3077
|
-
response = await client.
|
|
3077
|
+
response = await client._stub.ImageBuildChainGet(request)
|
|
3078
3078
|
self._build_steps = list(response.build_steps)
|
|
3079
3079
|
return _ImageLogQueryData(client, self._build_steps or [], image_id)
|
|
3080
3080
|
|
|
@@ -256,7 +256,7 @@ async def _refine_dense_ranges(
|
|
|
256
256
|
sandbox_id=filters.sandbox_id,
|
|
257
257
|
search_text=filters.search_text,
|
|
258
258
|
)
|
|
259
|
-
sub_resp = await client.
|
|
259
|
+
sub_resp = await client._stub.AppCountLogs(sub_req)
|
|
260
260
|
sub_ranges = _buckets_to_ranges(list(sub_resp.buckets), smaller_secs)
|
|
261
261
|
# Clamp the edge sub-ranges to the parent boundaries. Bucket
|
|
262
262
|
# alignment can make the first bucket begin before the parent
|
|
@@ -311,7 +311,7 @@ async def _fetch_interval(
|
|
|
311
311
|
sandbox_id=filters.sandbox_id,
|
|
312
312
|
search_text=filters.search_text,
|
|
313
313
|
)
|
|
314
|
-
resp: api_pb2.AppFetchLogsResponse = await client.
|
|
314
|
+
resp: api_pb2.AppFetchLogsResponse = await client._stub.AppFetchLogs(req)
|
|
315
315
|
return list(resp.batches)
|
|
316
316
|
|
|
317
317
|
|
|
@@ -365,7 +365,7 @@ async def tail_logs(
|
|
|
365
365
|
sandbox_id=filters.sandbox_id,
|
|
366
366
|
search_text=filters.search_text,
|
|
367
367
|
)
|
|
368
|
-
resp = await client.
|
|
368
|
+
resp = await client._stub.AppFetchLogs(req)
|
|
369
369
|
for batch in resp.batches:
|
|
370
370
|
yield batch
|
|
371
371
|
return
|
|
@@ -387,7 +387,7 @@ async def tail_logs(
|
|
|
387
387
|
sandbox_id=filters.sandbox_id,
|
|
388
388
|
search_text=filters.search_text,
|
|
389
389
|
)
|
|
390
|
-
resp = await client.
|
|
390
|
+
resp = await client._stub.AppFetchLogs(req)
|
|
391
391
|
|
|
392
392
|
total_items = sum(len(b.items) for b in resp.batches)
|
|
393
393
|
if total_items >= n or lookback == _TAIL_LOOKBACKS[-1]:
|
|
@@ -433,7 +433,7 @@ async def fetch_logs(
|
|
|
433
433
|
sandbox_id=filters.sandbox_id,
|
|
434
434
|
search_text=filters.search_text,
|
|
435
435
|
)
|
|
436
|
-
count_resp: api_pb2.AppCountLogsResponse = await client.
|
|
436
|
+
count_resp: api_pb2.AppCountLogsResponse = await client._stub.AppCountLogs(count_req)
|
|
437
437
|
|
|
438
438
|
ranges = _buckets_to_ranges(list(count_resp.buckets), bucket_secs)
|
|
439
439
|
total_logs = sum(count for _, _, count in ranges)
|
|
@@ -190,7 +190,7 @@ class _LogsManager:
|
|
|
190
190
|
task_id=params.filters.task_id,
|
|
191
191
|
sandbox_id=params.filters.sandbox_id,
|
|
192
192
|
)
|
|
193
|
-
return params.client.
|
|
193
|
+
return params.client._stub.AppGetLogs.unary_stream(request)
|
|
194
194
|
|
|
195
195
|
def _stream_entries(self, batch: api_pb2.TaskLogsBatch, source_object_id: str):
|
|
196
196
|
for item in batch.items:
|
|
@@ -544,7 +544,7 @@ class _FunctionCallLogsManager:
|
|
|
544
544
|
function_id=self._function_id,
|
|
545
545
|
function_call_id=params.filters.function_call_id,
|
|
546
546
|
)
|
|
547
|
-
response = await params.client.
|
|
547
|
+
response = await params.client._stub.FunctionCallGetInfo(request)
|
|
548
548
|
return response.info
|
|
549
549
|
except NotFoundError:
|
|
550
550
|
if i < 4:
|