modal 1.5.5.dev15__tar.gz → 1.5.5.dev17__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.5.dev15 → modal-1.5.5.dev17}/PKG-INFO +1 -1
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_environments.py +2 -2
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_function_variants.py +2 -2
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_functions.py +35 -4
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_image.py +4 -4
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_object.py +30 -3
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_resolver.py +5 -5
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_runtime/user_code_imports.py +5 -5
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_serialization.py +3 -1
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_utils/deprecation.py +29 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_utils/mount_utils.py +1 -1
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_workspace.py +6 -6
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/app.py +43 -17
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/cli/config.py +5 -1
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/cli/import_refs.py +9 -4
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/cli/launch.py +1 -1
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/cli/run.py +7 -7
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/cli/shell.py +2 -2
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/client.py +137 -20
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/client.pyi +124 -3
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/cls.py +22 -15
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/config.py +15 -7
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/exception.py +13 -2
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/object.pyi +7 -1
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/runner.py +6 -6
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/sandbox.py +62 -11
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/sandbox.pyi +12 -12
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal.egg-info/PKG-INFO +1 -1
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal_proto/api_grpc.py +16 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal_proto/api_pb2.py +838 -808
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal_proto/api_pb2.pyi +138 -5
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal_proto/api_pb2_grpc.py +33 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal_proto/api_pb2_grpc.pyi +10 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal_proto/modal_api_grpc.py +1 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal_proto/task_command_router_pb2.py +34 -34
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal_proto/task_command_router_pb2.pyi +15 -3
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal_version/__init__.py +1 -1
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/pyproject.toml +1 -1
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/LICENSE +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/README.md +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/__init__.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/__main__.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_billing.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_clustered_functions.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_clustered_functions.pyi +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_container_entrypoint.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_grpc_client.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_ipython.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_load_context.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_location.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_logs.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_logs_manager.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_logs_manager.pyi +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_output/__init__.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_output/manager.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_output/pty.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_output/rich.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_output/status.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_partial_function.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_resources.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_runtime/__init__.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_runtime/asgi.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_runtime/container_io_manager.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_runtime/container_io_manager.pyi +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_runtime/execution_context.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_runtime/execution_context.pyi +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_runtime/gpu_memory_snapshot.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_runtime/task_lifecycle_manager.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_runtime/task_lifecycle_manager.pyi +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_runtime/telemetry.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_runtime/user_code_event_loop.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_server.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_supports_logs.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_traceback.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_tunnel.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_tunnel.pyi +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_type_manager.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_utils/__init__.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_utils/app_utils.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_utils/async_utils.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_utils/auth_token_manager.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_utils/blob_utils.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_utils/browser_utils.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_utils/bytes_io_segment_payload.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_utils/curl_utils.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_utils/display_utils.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_utils/docker_utils.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_utils/function_utils.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_utils/git_utils.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_utils/grpc_testing.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_utils/grpc_utils.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_utils/hash_utils.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_utils/http_utils.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_utils/jwt_utils.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_utils/logger.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_utils/name_utils.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_utils/package_utils.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_utils/pattern_utils.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_utils/proxy_support.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_utils/rand_pb_testing.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_utils/sandbox_fs_utils.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_utils/shell_utils.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_utils/task_command_router_client.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_utils/time_utils.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_vendor/__init__.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_vendor/a2wsgi_wsgi.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_vendor/cloudpickle.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_vendor/tblib.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_vendor/version.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/_watcher.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/app.pyi +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/billing.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/billing.pyi +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/builder/2023.12.312.txt +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/builder/2023.12.txt +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/builder/2024.04.txt +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/builder/2024.10.txt +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/builder/2025.06.txt +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/builder/PREVIEW.txt +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/builder/README.md +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/builder/base-images.json +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/call_graph.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/cli/__init__.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/cli/_download.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/cli/_help.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/cli/_traceback.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/cli/app.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/cli/billing.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/cli/bootstrap.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/cli/changelog.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/cli/cluster.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/cli/container.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/cli/curl.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/cli/dashboard.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/cli/dict.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/cli/endpoint.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/cli/entry_point.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/cli/environment.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/cli/image.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/cli/logo.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/cli/network_file_system.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/cli/profile.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/cli/programs/__init__.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/cli/programs/run_jupyter.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/cli/programs/vscode.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/cli/queues.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/cli/secret.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/cli/selector.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/cli/skills.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/cli/token.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/cli/utils.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/cli/volume.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/cli/workspace.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/cloud_bucket_mount.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/cloud_bucket_mount.pyi +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/cls.pyi +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/container_process.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/container_process.pyi +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/dict.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/dict.pyi +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/environments.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/environments.pyi +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/experimental/__init__.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/experimental/flash.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/experimental/flash.pyi +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/experimental/ipython.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/file_io.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/file_io.pyi +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/file_pattern_matcher.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/functions.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/functions.pyi +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/image.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/image.pyi +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/io_streams.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/io_streams.pyi +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/mount.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/mount.pyi +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/network_file_system.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/network_file_system.pyi +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/object.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/output.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/parallel_map.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/parallel_map.pyi +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/partial_function.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/partial_function.pyi +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/proxy.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/proxy.pyi +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/py.typed +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/queue.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/queue.pyi +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/retries.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/runner.pyi +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/running_app.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/sandbox_fs.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/sandbox_fs.pyi +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/schedule.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/scheduler_placement.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/secret.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/secret.pyi +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/server.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/server.pyi +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/serving.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/serving.pyi +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/skills/modal/SKILL.md +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/snapshot.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/snapshot.pyi +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/stream_type.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/token_flow.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/token_flow.pyi +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/types.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/volume.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/volume.pyi +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/workspace.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal/workspace.pyi +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal.egg-info/SOURCES.txt +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal.egg-info/dependency_links.txt +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal.egg-info/entry_points.txt +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal.egg-info/requires.txt +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal.egg-info/top_level.txt +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal_docs/__init__.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal_docs/gen_cli_docs.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal_docs/gen_cli_docs_main.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal_docs/gen_reference_docs.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal_docs/gen_reference_docs_main.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal_docs/mdmd/__init__.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal_docs/mdmd/mdmd.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal_docs/mdmd/signatures.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal_docs/mdmd/types.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal_docs/reference_intro.md +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal_proto/__init__.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal_proto/py.typed +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal_proto/task_command_router_grpc.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal_proto/task_command_router_pb2_grpc.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal_proto/task_command_router_pb2_grpc.pyi +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/modal_version/__main__.py +0 -0
- {modal-1.5.5.dev15 → modal-1.5.5.dev17}/setup.cfg +0 -0
|
@@ -478,7 +478,7 @@ class _EnvironmentBillingManager:
|
|
|
478
478
|
elif end.tzinfo != timezone.utc:
|
|
479
479
|
raise InvalidError("Timezone-aware 'end' parameter must be in UTC.")
|
|
480
480
|
|
|
481
|
-
if not self._environment.
|
|
481
|
+
if not self._environment._is_hydrated:
|
|
482
482
|
await self._environment.hydrate()
|
|
483
483
|
|
|
484
484
|
request = api_pb2.WorkspaceBillingReportRequest(
|
|
@@ -549,7 +549,7 @@ class _EnvironmentBillingManager:
|
|
|
549
549
|
if cycle > datetime.now(timezone.utc):
|
|
550
550
|
raise InvalidError("Provided 'cycle' parameter cannot be in the future.")
|
|
551
551
|
|
|
552
|
-
if not self._environment.
|
|
552
|
+
if not self._environment._is_hydrated:
|
|
553
553
|
await self._environment.hydrate()
|
|
554
554
|
|
|
555
555
|
request = api_pb2.EnvironmentBillingSummaryRequest(environment_id=self._environment.object_id)
|
|
@@ -157,7 +157,7 @@ class _FunctionOptions:
|
|
|
157
157
|
+ list(self.secrets)
|
|
158
158
|
+ [mount.secret for _, mount in self.cloud_bucket_mounts if mount.secret]
|
|
159
159
|
)
|
|
160
|
-
return [dep for dep in all_deps if not dep.
|
|
160
|
+
return [dep for dep in all_deps if not dep._is_hydrated]
|
|
161
161
|
|
|
162
162
|
def to_proto(self) -> api_pb2.FunctionOptions:
|
|
163
163
|
"""Convert the dataclass to a FunctionOptions protobuf message."""
|
|
@@ -246,7 +246,7 @@ def _make_function_variant(
|
|
|
246
246
|
load_context: "LoadContext",
|
|
247
247
|
existing_object_id: str | None,
|
|
248
248
|
):
|
|
249
|
-
if not base_function.
|
|
249
|
+
if not base_function._is_hydrated:
|
|
250
250
|
await base_function.hydrate(load_context.client)
|
|
251
251
|
assert base_function._client and base_function._client.stub
|
|
252
252
|
|
|
@@ -46,6 +46,7 @@ from ._utils.async_utils import (
|
|
|
46
46
|
warn_if_generator_is_not_consumed,
|
|
47
47
|
)
|
|
48
48
|
from ._utils.blob_utils import MAX_ASYNC_OBJECT_SIZE_BYTES, MAX_OBJECT_SIZE_BYTES
|
|
49
|
+
from ._utils.deprecation import with_deprecation_warning
|
|
49
50
|
from ._utils.function_utils import (
|
|
50
51
|
ATTEMPT_TIMEOUT_GRACE_PERIOD,
|
|
51
52
|
OUTPUTS_TIMEOUT,
|
|
@@ -937,7 +938,7 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
|
|
|
937
938
|
with FunctionCreationStatus(tag) as function_creation_status:
|
|
938
939
|
timeout_secs = timeout
|
|
939
940
|
|
|
940
|
-
if app and app.
|
|
941
|
+
if app and app._is_interactive_ and not is_builder_function:
|
|
941
942
|
pty_info = get_pty_info(shell=False)
|
|
942
943
|
else:
|
|
943
944
|
pty_info = None
|
|
@@ -1194,7 +1195,10 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
|
|
|
1194
1195
|
|
|
1195
1196
|
return obj
|
|
1196
1197
|
|
|
1197
|
-
from_local =
|
|
1198
|
+
from_local = with_deprecation_warning(
|
|
1199
|
+
(2026, 8, 26),
|
|
1200
|
+
"`Function.from_local` is deprecated and will be removed in `modal` version 1.6.0",
|
|
1201
|
+
)(_from_local)
|
|
1198
1202
|
"""mdmd:hidden"""
|
|
1199
1203
|
|
|
1200
1204
|
async def _update_autoscaler(
|
|
@@ -1389,6 +1393,10 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
|
|
|
1389
1393
|
)
|
|
1390
1394
|
|
|
1391
1395
|
@property
|
|
1396
|
+
@with_deprecation_warning(
|
|
1397
|
+
(2026, 8, 26),
|
|
1398
|
+
"`Function.tag` is deprecated and will be removed in `modal` version 1.6.0",
|
|
1399
|
+
)
|
|
1392
1400
|
def tag(self) -> str:
|
|
1393
1401
|
"""mdmd:hidden"""
|
|
1394
1402
|
return self._tag_
|
|
@@ -1407,12 +1415,20 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
|
|
|
1407
1415
|
return self._app
|
|
1408
1416
|
|
|
1409
1417
|
@property
|
|
1418
|
+
@with_deprecation_warning(
|
|
1419
|
+
(2026, 8, 26),
|
|
1420
|
+
"`Function.stub` is deprecated and will be removed in `modal` version 1.6.0",
|
|
1421
|
+
)
|
|
1410
1422
|
def stub(self) -> "modal.app._App":
|
|
1411
1423
|
"""mdmd:hidden"""
|
|
1412
1424
|
# Deprecated soon, only for backwards compatibility
|
|
1413
1425
|
return self.app
|
|
1414
1426
|
|
|
1415
1427
|
@property
|
|
1428
|
+
@with_deprecation_warning(
|
|
1429
|
+
(2026, 8, 26),
|
|
1430
|
+
"`Function.info` is deprecated and will be removed in `modal` version 1.6.0",
|
|
1431
|
+
)
|
|
1416
1432
|
def info(self) -> FunctionInfo:
|
|
1417
1433
|
"""mdmd:hidden"""
|
|
1418
1434
|
return self._info_
|
|
@@ -1423,6 +1439,10 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
|
|
|
1423
1439
|
return self._info
|
|
1424
1440
|
|
|
1425
1441
|
@property
|
|
1442
|
+
@with_deprecation_warning(
|
|
1443
|
+
(2026, 8, 26),
|
|
1444
|
+
"`Function.spec` is deprecated and will be removed in `modal` version 1.6.0",
|
|
1445
|
+
)
|
|
1426
1446
|
def spec(self) -> _FunctionSpec:
|
|
1427
1447
|
"""mdmd:hidden"""
|
|
1428
1448
|
return self._spec_
|
|
@@ -1443,7 +1463,10 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
|
|
|
1443
1463
|
assert hasattr(self, "_raw_f") and hasattr(self, "_build_args") and self._raw_f is not None
|
|
1444
1464
|
return f"{inspect.getsource(self._raw_f)}\n{repr(self._build_args)}"
|
|
1445
1465
|
|
|
1446
|
-
get_build_def =
|
|
1466
|
+
get_build_def = with_deprecation_warning(
|
|
1467
|
+
(2026, 8, 26),
|
|
1468
|
+
"`Function.get_build_def` is deprecated and will be removed in `modal` version 1.6.0",
|
|
1469
|
+
)(_get_build_def)
|
|
1447
1470
|
"""mdmd:hidden"""
|
|
1448
1471
|
|
|
1449
1472
|
# Live handle methods
|
|
@@ -1693,6 +1716,10 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
|
|
|
1693
1716
|
return self._apply_dynamic_config(options, "with_batching")
|
|
1694
1717
|
|
|
1695
1718
|
@property
|
|
1719
|
+
@with_deprecation_warning(
|
|
1720
|
+
(2026, 8, 26),
|
|
1721
|
+
"`Function.is_generator` is deprecated and will be removed in `modal` version 1.6.0",
|
|
1722
|
+
)
|
|
1696
1723
|
async def is_generator(self) -> bool:
|
|
1697
1724
|
"""mdmd:hidden"""
|
|
1698
1725
|
return await self._is_generator_
|
|
@@ -1934,7 +1961,7 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
|
|
|
1934
1961
|
# TODO: check if we end up here in a container for a serialized function?
|
|
1935
1962
|
raise ExecutionError("Can't call .local on service function")
|
|
1936
1963
|
|
|
1937
|
-
if is_local() and self.
|
|
1964
|
+
if is_local() and self._spec_.volumes or self._spec_.network_file_systems:
|
|
1938
1965
|
warnings.warn(
|
|
1939
1966
|
f"The {info.function_name} function is executing locally "
|
|
1940
1967
|
+ "and will not have access to the mounted Volume or NetworkFileSystem data"
|
|
@@ -2032,6 +2059,10 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
|
|
|
2032
2059
|
fc._function_id = self.object_id
|
|
2033
2060
|
return fc
|
|
2034
2061
|
|
|
2062
|
+
@with_deprecation_warning(
|
|
2063
|
+
(2026, 8, 26),
|
|
2064
|
+
"`Function.get_raw_f` is deprecated and will be removed in `modal` version 1.6.0",
|
|
2065
|
+
)
|
|
2035
2066
|
def get_raw_f(self) -> Callable[..., Any]:
|
|
2036
2067
|
"""Return the inner Python object wrapped by this Modal Function.
|
|
2037
2068
|
|
|
@@ -704,7 +704,7 @@ class _Image(_Object, type_prefix="im"):
|
|
|
704
704
|
# TODO: better way to filter out types that don't have a stable hash?
|
|
705
705
|
build_function_globals = serialize(filtered_globals) if filtered_globals else b""
|
|
706
706
|
_build_function = api_pb2.BuildFunction(
|
|
707
|
-
definition=build_function.
|
|
707
|
+
definition=build_function._get_build_def(),
|
|
708
708
|
globals=build_function_globals,
|
|
709
709
|
input=build_function_input,
|
|
710
710
|
)
|
|
@@ -2756,7 +2756,7 @@ class _Image(_Object, type_prefix="im"):
|
|
|
2756
2756
|
|
|
2757
2757
|
info = FunctionInfo(raw_f)
|
|
2758
2758
|
|
|
2759
|
-
function = _Function.
|
|
2759
|
+
function = _Function._from_local(
|
|
2760
2760
|
info,
|
|
2761
2761
|
app=None,
|
|
2762
2762
|
image=self,
|
|
@@ -2938,7 +2938,7 @@ class _Image(_Object, type_prefix="im"):
|
|
|
2938
2938
|
try:
|
|
2939
2939
|
yield
|
|
2940
2940
|
except Exception as exc:
|
|
2941
|
-
if not self.
|
|
2941
|
+
if not self._is_hydrated:
|
|
2942
2942
|
# Might be hydrated later (if it's the container's used image)
|
|
2943
2943
|
self.inside_exceptions.append(exc)
|
|
2944
2944
|
elif env_image_id == self.object_id:
|
|
@@ -3051,7 +3051,7 @@ class _Image(_Object, type_prefix="im"):
|
|
|
3051
3051
|
"""mdmd:hidden"""
|
|
3052
3052
|
# Image inherits hydrate() from Object but can't be hydrated on demand
|
|
3053
3053
|
# Overriding the method lets us hide it from the docs and raise a better error message
|
|
3054
|
-
if not self.
|
|
3054
|
+
if not self._is_hydrated:
|
|
3055
3055
|
raise ExecutionError(
|
|
3056
3056
|
"Images cannot currently be hydrated on demand; you can build an Image by running an App that uses it."
|
|
3057
3057
|
)
|
|
@@ -9,11 +9,11 @@ from typing import ClassVar
|
|
|
9
9
|
from google.protobuf.message import Message
|
|
10
10
|
from typing_extensions import Self
|
|
11
11
|
|
|
12
|
-
from modal._traceback import suppress_tb_frame
|
|
13
|
-
|
|
14
12
|
from ._load_context import LoadContext
|
|
15
13
|
from ._resolver import Resolver
|
|
14
|
+
from ._traceback import suppress_tb_frame
|
|
16
15
|
from ._utils.async_utils import TaskContext, aclosing
|
|
16
|
+
from ._utils.deprecation import deprecation_warning
|
|
17
17
|
from .client import _Client
|
|
18
18
|
from .config import config, logger
|
|
19
19
|
from .exception import ExecutionError, InvalidError
|
|
@@ -91,13 +91,21 @@ class _Object:
|
|
|
91
91
|
# For hydrated objects
|
|
92
92
|
_object_id: str | None
|
|
93
93
|
_client: _Client | None
|
|
94
|
-
|
|
94
|
+
__is_hydrated: bool
|
|
95
95
|
_is_rehydrated: bool
|
|
96
96
|
|
|
97
97
|
# Not all object subclasses have a meaningful "name" concept
|
|
98
98
|
# So whether they expose this is a matter of having a name property
|
|
99
99
|
_name: str | None
|
|
100
100
|
|
|
101
|
+
@property
|
|
102
|
+
def _is_hydrated(self) -> bool:
|
|
103
|
+
return self.__is_hydrated
|
|
104
|
+
|
|
105
|
+
@_is_hydrated.setter
|
|
106
|
+
def _is_hydrated(self, value: bool):
|
|
107
|
+
self.__is_hydrated = value
|
|
108
|
+
|
|
101
109
|
@classmethod
|
|
102
110
|
def __init_subclass__(cls, type_prefix: str | None = None):
|
|
103
111
|
super().__init_subclass__()
|
|
@@ -281,9 +289,18 @@ class _Object:
|
|
|
281
289
|
def __repr__(self):
|
|
282
290
|
return self._rep
|
|
283
291
|
|
|
292
|
+
@property
|
|
293
|
+
def _class_name(self):
|
|
294
|
+
return self.__class__.__name__.removeprefix("_")
|
|
295
|
+
|
|
284
296
|
@property
|
|
285
297
|
def local_uuid(self):
|
|
286
298
|
"""mdmd:hidden"""
|
|
299
|
+
deprecation_warning(
|
|
300
|
+
(2026, 8, 26),
|
|
301
|
+
f"`{self._class_name}.local_uuid` is deprecated and will be removed in `modal` version 1.6.0",
|
|
302
|
+
)
|
|
303
|
+
|
|
287
304
|
return self._local_uuid
|
|
288
305
|
|
|
289
306
|
@property
|
|
@@ -308,11 +325,21 @@ class _Object:
|
|
|
308
325
|
@property
|
|
309
326
|
def is_hydrated(self) -> bool:
|
|
310
327
|
"""mdmd:hidden"""
|
|
328
|
+
deprecation_warning(
|
|
329
|
+
(2026, 8, 26),
|
|
330
|
+
f"`{self._class_name}.is_hydrated` is deprecated and will be removed in `modal` version 1.6.0",
|
|
331
|
+
)
|
|
332
|
+
|
|
311
333
|
return self._is_hydrated
|
|
312
334
|
|
|
313
335
|
@property
|
|
314
336
|
def deps(self) -> Callable[..., Sequence["_Object"]]:
|
|
315
337
|
"""mdmd:hidden"""
|
|
338
|
+
deprecation_warning(
|
|
339
|
+
(2026, 8, 26),
|
|
340
|
+
f"`{self._class_name}.deps` is deprecated and will be removed in `modal` version 1.6.0",
|
|
341
|
+
)
|
|
342
|
+
|
|
316
343
|
return self._deps_
|
|
317
344
|
|
|
318
345
|
@property
|
|
@@ -44,19 +44,19 @@ class Resolver:
|
|
|
44
44
|
existing_object_id: str | None = None,
|
|
45
45
|
):
|
|
46
46
|
if obj._is_hydrated and obj._skip_reload:
|
|
47
|
-
if obj.
|
|
47
|
+
if obj._local_uuid not in self._local_uuid_to_future:
|
|
48
48
|
# a bit dumb - but we still need to store a reference to the object here
|
|
49
49
|
# to be able to include all referenced objects when setting up the app
|
|
50
50
|
fut: Future = Future()
|
|
51
51
|
fut.set_result(obj)
|
|
52
|
-
self._local_uuid_to_future[obj.
|
|
52
|
+
self._local_uuid_to_future[obj._local_uuid] = fut
|
|
53
53
|
return obj
|
|
54
54
|
|
|
55
55
|
deduplication_key: Hashable | None = None
|
|
56
56
|
if obj._deduplication_key:
|
|
57
57
|
deduplication_key = await obj._deduplication_key()
|
|
58
58
|
|
|
59
|
-
cached_future = self._local_uuid_to_future.get(obj.
|
|
59
|
+
cached_future = self._local_uuid_to_future.get(obj._local_uuid)
|
|
60
60
|
|
|
61
61
|
if not cached_future and deduplication_key is not None:
|
|
62
62
|
# deduplication cache makes sure duplicate mounts are resolved only
|
|
@@ -78,7 +78,7 @@ class Resolver:
|
|
|
78
78
|
# Use asyncio.gather here (not TaskContext.gather) - the shared TaskContext
|
|
79
79
|
# in load_context handles cancellation at the top level, preventing premature
|
|
80
80
|
# cancellation of shared dependencies when sibling tasks fail.
|
|
81
|
-
await asyncio.gather(*[self.load(dep, load_context) for dep in obj.
|
|
81
|
+
await asyncio.gather(*[self.load(dep, load_context) for dep in obj._deps_()])
|
|
82
82
|
|
|
83
83
|
# Load the object itself
|
|
84
84
|
if not obj._load:
|
|
@@ -102,7 +102,7 @@ class Resolver:
|
|
|
102
102
|
|
|
103
103
|
# use task_context from load_context to make sure tasks are cleaned up eventually
|
|
104
104
|
cached_future = parent_load_context.task_context.create_task(loader())
|
|
105
|
-
self._local_uuid_to_future[obj.
|
|
105
|
+
self._local_uuid_to_future[obj._local_uuid] = cached_future
|
|
106
106
|
if deduplication_key is not None:
|
|
107
107
|
self._deduplication_cache[deduplication_key] = cached_future
|
|
108
108
|
with suppress_tb_frame():
|
|
@@ -522,8 +522,8 @@ def import_single_function_service(
|
|
|
522
522
|
f = getattr(module, qual_name)
|
|
523
523
|
if isinstance(f, Function):
|
|
524
524
|
_function: modal._functions._Function[Any, Any, Any] = synchronizer._translate_in(f) # type: ignore
|
|
525
|
-
service_deps = _function.
|
|
526
|
-
user_defined_callable = _function.
|
|
525
|
+
service_deps = _function._deps_(only_explicit_mounts=True)
|
|
526
|
+
user_defined_callable = _function._raw_f_
|
|
527
527
|
assert _function._app # app should always be set on a decorated function
|
|
528
528
|
active_app = _function._app
|
|
529
529
|
else:
|
|
@@ -594,7 +594,7 @@ def import_class_service(
|
|
|
594
594
|
if isinstance(cls_or_user_cls, modal.cls.Cls):
|
|
595
595
|
_cls = typing.cast(modal.cls._Cls, synchronizer._translate_in(cls_or_user_cls))
|
|
596
596
|
class_service_function: _Function = _cls._get_class_service_function()
|
|
597
|
-
service_deps = class_service_function.
|
|
597
|
+
service_deps = class_service_function._deps_(only_explicit_mounts=True)
|
|
598
598
|
active_app = class_service_function.app
|
|
599
599
|
else:
|
|
600
600
|
# Undecorated user class (serialized or local scope-decoration).
|
|
@@ -606,7 +606,7 @@ def import_class_service(
|
|
|
606
606
|
service_function_hydration_data.function_handle_metadata,
|
|
607
607
|
skip_reload=True, # this skips re-loading the function, which is required since it doesn't have a loader
|
|
608
608
|
)
|
|
609
|
-
_cls = modal.cls._Cls.
|
|
609
|
+
_cls = modal.cls._Cls._from_local(cls_or_user_cls, active_app, _service_function)
|
|
610
610
|
# hydration of the class itself - just sets the id and triggers some side effects
|
|
611
611
|
# that transfers metadata from the service function to the class. TODO: cleanup!
|
|
612
612
|
_cls._hydrate(class_id, _client, api_pb2.ClassHandleMetadata())
|
|
@@ -647,7 +647,7 @@ def import_server_service(
|
|
|
647
647
|
if isinstance(cls_or_user_cls, modal.server.Server):
|
|
648
648
|
_server = typing.cast(modal._server._Server, synchronizer._translate_in(cls_or_user_cls))
|
|
649
649
|
server_service_function: _Function = _server._get_service_function()
|
|
650
|
-
service_deps = server_service_function.
|
|
650
|
+
service_deps = server_service_function._deps_(only_explicit_mounts=True)
|
|
651
651
|
active_app = _server._get_app()
|
|
652
652
|
|
|
653
653
|
else:
|
|
@@ -66,8 +66,10 @@ class Pickler(cloudpickle.Pickler):
|
|
|
66
66
|
return ("sync", (impl_object.__class__, attributes))
|
|
67
67
|
else:
|
|
68
68
|
return
|
|
69
|
-
|
|
69
|
+
|
|
70
|
+
if not obj._is_hydrated:
|
|
70
71
|
raise InvalidError(f"Can't serialize object {obj} which hasn't been hydrated.")
|
|
72
|
+
|
|
71
73
|
return (obj.object_id, flag, obj._get_metadata())
|
|
72
74
|
|
|
73
75
|
|
|
@@ -118,3 +118,32 @@ def handle_deprecated_parameters(func: Callable[P, R]) -> Callable[P, R]:
|
|
|
118
118
|
return func(*args, **kwargs)
|
|
119
119
|
|
|
120
120
|
return wrapper
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def with_deprecation_warning(
|
|
124
|
+
deprecated_on: tuple[int, int, int], msg: str, *, show_source: bool = True
|
|
125
|
+
) -> Callable[[Callable[P, R]], Callable[P, R]]:
|
|
126
|
+
def decorator(method: Callable[P, R]) -> Callable[P, R]:
|
|
127
|
+
is_static = False
|
|
128
|
+
if isinstance(method, staticmethod):
|
|
129
|
+
is_static = True
|
|
130
|
+
method = method.__wrapped__
|
|
131
|
+
|
|
132
|
+
# Note: despite `wrapped` being synchronous, this also works with async functions, in that if
|
|
133
|
+
# a function returns a coroutine, then this function will also return a coroutine. So, when
|
|
134
|
+
# called from an async context, the return can be awaited without issues. However, code that
|
|
135
|
+
# introspects `wrapped` with, e.g. inspect.iscoroutinefunction(), will not pick up on the
|
|
136
|
+
# fact that it returns a coroutine unless it unwraps `wrapped` and tries to introspect `method`
|
|
137
|
+
# directly. Synchronicity already does this (https://github.com/modal-labs/synchronicity/blob/441085df7dfa953c86304d06da5e0e74cebbe858/src/synchronicity/async_wrap.py#L42-L57),
|
|
138
|
+
# but this is fixable on Python >= 3.12, which adds `inspect.markcoroutinefunction`.
|
|
139
|
+
@functools.wraps(method)
|
|
140
|
+
def wrapped(*args: P.args, **kwargs: P.kwargs) -> R:
|
|
141
|
+
deprecation_warning(deprecated_on, msg, show_source=show_source)
|
|
142
|
+
return method(*args, **kwargs)
|
|
143
|
+
|
|
144
|
+
if is_static:
|
|
145
|
+
return staticmethod(wrapped)
|
|
146
|
+
|
|
147
|
+
return wrapped
|
|
148
|
+
|
|
149
|
+
return decorator
|
|
@@ -108,7 +108,7 @@ def validate_volumes_by_object_id(validated_volumes: Sequence[tuple[str, _Volume
|
|
|
108
108
|
"""
|
|
109
109
|
object_id_to_paths: dict[str, list[str]] = {}
|
|
110
110
|
for path, volume in validated_volumes:
|
|
111
|
-
if not volume.
|
|
111
|
+
if not volume._is_hydrated:
|
|
112
112
|
# This should never happen since this function is only called at load time
|
|
113
113
|
raise RuntimeError(f"Internal error: Volume at '{path}' is not hydrated when validating mounts")
|
|
114
114
|
object_id_to_paths.setdefault(volume.object_id, []).append(path)
|
|
@@ -321,7 +321,7 @@ class _WorkspaceBillingManager:
|
|
|
321
321
|
A single mapping containing cost values. All values are reported as `decimal.Decimal`s.
|
|
322
322
|
"""
|
|
323
323
|
|
|
324
|
-
if not self._workspace.
|
|
324
|
+
if not self._workspace._is_hydrated:
|
|
325
325
|
await self._workspace.hydrate()
|
|
326
326
|
|
|
327
327
|
response = await self._workspace.client.stub.WorkspaceBillingRates(
|
|
@@ -386,7 +386,7 @@ class _WorkspaceBillingManager:
|
|
|
386
386
|
elif end.tzinfo != timezone.utc:
|
|
387
387
|
raise InvalidError("Timezone-aware 'end' parameter must be in UTC.")
|
|
388
388
|
|
|
389
|
-
if not self._workspace.
|
|
389
|
+
if not self._workspace._is_hydrated:
|
|
390
390
|
await self._workspace.hydrate()
|
|
391
391
|
|
|
392
392
|
request = api_pb2.WorkspaceBillingReportRequest(
|
|
@@ -457,7 +457,7 @@ class _WorkspaceBillingManager:
|
|
|
457
457
|
if cycle > datetime.now(timezone.utc):
|
|
458
458
|
raise InvalidError("Provided 'cycle' parameter cannot be in the future.")
|
|
459
459
|
|
|
460
|
-
if not self._workspace.
|
|
460
|
+
if not self._workspace._is_hydrated:
|
|
461
461
|
await self._workspace.hydrate()
|
|
462
462
|
|
|
463
463
|
request = api_pb2.WorkspaceBillingSummaryRequest()
|
|
@@ -483,7 +483,7 @@ class _WorkspaceSettingsManager:
|
|
|
483
483
|
Returns:
|
|
484
484
|
A `WorkspaceSettings` dataclass.
|
|
485
485
|
"""
|
|
486
|
-
if not self._workspace.
|
|
486
|
+
if not self._workspace._is_hydrated:
|
|
487
487
|
await self._workspace.hydrate()
|
|
488
488
|
resp = await self._workspace.client.stub.WorkspaceSettings(Empty())
|
|
489
489
|
return WorkspaceSettings(
|
|
@@ -494,14 +494,14 @@ class _WorkspaceSettingsManager:
|
|
|
494
494
|
"""mdmd:hidden
|
|
495
495
|
Set the image builder version for the Workspace.
|
|
496
496
|
"""
|
|
497
|
-
if not self._workspace.
|
|
497
|
+
if not self._workspace._is_hydrated:
|
|
498
498
|
await self._workspace.hydrate()
|
|
499
499
|
req = api_pb2.WorkspaceSetImageBuilderVersionRequest(new_image_builder_version=version)
|
|
500
500
|
await self._workspace.client.stub.WorkspaceSetImageBuilderVersion(req)
|
|
501
501
|
|
|
502
502
|
async def _set_default_environment(self, name: str) -> None:
|
|
503
503
|
"""Set the default environment for the Workspace."""
|
|
504
|
-
if not self._workspace.
|
|
504
|
+
if not self._workspace._is_hydrated:
|
|
505
505
|
await self._workspace.hydrate()
|
|
506
506
|
req = api_pb2.WorkspaceSetDefaultEnvironmentRequest(environment_name=name)
|
|
507
507
|
await self._workspace.client.stub.WorkspaceSetDefaultEnvironment(req)
|
|
@@ -33,10 +33,7 @@ from ._partial_function import (
|
|
|
33
33
|
from ._server import _Server, validate_http_server_config
|
|
34
34
|
from ._supports_logs import _LogQueryData
|
|
35
35
|
from ._utils.async_utils import synchronize_api
|
|
36
|
-
from ._utils.deprecation import
|
|
37
|
-
deprecation_warning,
|
|
38
|
-
handle_deprecated_parameters,
|
|
39
|
-
)
|
|
36
|
+
from ._utils.deprecation import deprecation_warning, handle_deprecated_parameters, with_deprecation_warning
|
|
40
37
|
from ._utils.function_utils import (
|
|
41
38
|
FunctionInfo,
|
|
42
39
|
is_flash_object,
|
|
@@ -274,6 +271,10 @@ class _App:
|
|
|
274
271
|
return self._name
|
|
275
272
|
|
|
276
273
|
@property
|
|
274
|
+
@with_deprecation_warning(
|
|
275
|
+
(2026, 8, 26),
|
|
276
|
+
"`App.is_interactive` is deprecated and will be removed in `modal` version 1.6.0",
|
|
277
|
+
)
|
|
277
278
|
def is_interactive(self) -> bool:
|
|
278
279
|
"""mdmd:hidden"""
|
|
279
280
|
return self._is_interactive_
|
|
@@ -383,6 +384,11 @@ class _App:
|
|
|
383
384
|
raise InvalidError("App is not running")
|
|
384
385
|
return f"https://modal.com/id/{self._app_id}"
|
|
385
386
|
|
|
387
|
+
@with_deprecation_warning(
|
|
388
|
+
(2026, 8, 26),
|
|
389
|
+
"`App.set_description` is deprecated and will be removed in `modal` version 1.6.0. "
|
|
390
|
+
"Set `App.description` directly instead",
|
|
391
|
+
)
|
|
386
392
|
def set_description(self, description: str):
|
|
387
393
|
"""mdmd:hidden
|
|
388
394
|
Set the description of the App before it starts running.
|
|
@@ -396,6 +402,10 @@ class _App:
|
|
|
396
402
|
raise InvalidError(f"App attribute `{key}` with value {value!r} is not a valid Modal object")
|
|
397
403
|
|
|
398
404
|
@property
|
|
405
|
+
@with_deprecation_warning(
|
|
406
|
+
(2026, 8, 26),
|
|
407
|
+
"`App.image` is deprecated and will be removed in `modal` version 1.6.0",
|
|
408
|
+
)
|
|
399
409
|
def image(self) -> _Image:
|
|
400
410
|
"""mdmd:hidden
|
|
401
411
|
Retrieve the Image that will be used as the default for any Functions registered to the App.
|
|
@@ -599,14 +609,14 @@ class _App:
|
|
|
599
609
|
raise ExecutionError("`_get_watch_mounts` requires a running app.")
|
|
600
610
|
|
|
601
611
|
all_mounts = []
|
|
602
|
-
for function in self.
|
|
612
|
+
for function in self._local_state.functions.values():
|
|
603
613
|
all_mounts.extend(function._serve_mounts)
|
|
604
614
|
|
|
605
615
|
return [m for m in all_mounts if m.is_local()]
|
|
606
616
|
|
|
607
617
|
def _add_function(self, function: _Function, is_web_endpoint: bool):
|
|
608
618
|
local_state = self._local_state
|
|
609
|
-
if old_function := local_state.functions.get(function.
|
|
619
|
+
if old_function := local_state.functions.get(function._tag_, None):
|
|
610
620
|
if old_function is function:
|
|
611
621
|
return # already added the same exact instance, ignore
|
|
612
622
|
|
|
@@ -615,25 +625,25 @@ class _App:
|
|
|
615
625
|
# and we don't want to warn about a collision in that case.
|
|
616
626
|
if not is_interactive_ipython():
|
|
617
627
|
logger.warning(
|
|
618
|
-
f"Warning: function name '{function.
|
|
628
|
+
f"Warning: function name '{function._tag_}' collision!"
|
|
619
629
|
" Overriding existing function "
|
|
620
630
|
f"[{old_function._info.module_name}].{old_function._info.function_name}"
|
|
621
631
|
f" with new function [{function._info.module_name}].{function._info.function_name}"
|
|
622
632
|
)
|
|
623
|
-
if function.
|
|
624
|
-
logger.warning(f"Warning: tag {function.
|
|
633
|
+
if function._tag_ in local_state.classes:
|
|
634
|
+
logger.warning(f"Warning: tag {function._tag_} exists but is overridden by function")
|
|
625
635
|
|
|
626
636
|
if self._running_app:
|
|
627
637
|
# If this is inside a container, then objects can be defined after app initialization.
|
|
628
638
|
# So we may have to initialize objects once they get bound to the app.
|
|
629
|
-
if function.
|
|
630
|
-
object_id: str = self._running_app.function_ids[function.
|
|
639
|
+
if function._tag_ in self._running_app.function_ids:
|
|
640
|
+
object_id: str = self._running_app.function_ids[function._tag_]
|
|
631
641
|
metadata: Message = self._running_app.object_handle_metadata[object_id]
|
|
632
642
|
function._hydrate(object_id, self._client, metadata)
|
|
633
643
|
|
|
634
|
-
local_state.functions[function.
|
|
644
|
+
local_state.functions[function._tag_] = function
|
|
635
645
|
if is_web_endpoint:
|
|
636
|
-
local_state.web_endpoints.append(function.
|
|
646
|
+
local_state.web_endpoints.append(function._tag_)
|
|
637
647
|
|
|
638
648
|
def _add_class(self, tag: str, cls: _Cls):
|
|
639
649
|
if self._running_app:
|
|
@@ -668,6 +678,10 @@ class _App:
|
|
|
668
678
|
obj._hydrate(object_id, client, handle_metadata)
|
|
669
679
|
|
|
670
680
|
@property
|
|
681
|
+
@with_deprecation_warning(
|
|
682
|
+
(2026, 8, 26),
|
|
683
|
+
"`App.registered_functions` is deprecated and will be removed in `modal` version 1.6.0",
|
|
684
|
+
)
|
|
671
685
|
def registered_functions(self) -> dict[str, _Function]:
|
|
672
686
|
"""mdmd:hidden
|
|
673
687
|
All modal.Function objects registered on the app.
|
|
@@ -680,6 +694,10 @@ class _App:
|
|
|
680
694
|
return self._local_state.functions
|
|
681
695
|
|
|
682
696
|
@property
|
|
697
|
+
@with_deprecation_warning(
|
|
698
|
+
(2026, 8, 26),
|
|
699
|
+
"`App.registered_classes` is deprecated and will be removed in `modal` version 1.6.0",
|
|
700
|
+
)
|
|
683
701
|
def registered_classes(self) -> dict[str, _Cls]:
|
|
684
702
|
"""mdmd:hidden
|
|
685
703
|
All modal.Cls objects registered on the app.
|
|
@@ -692,6 +710,10 @@ class _App:
|
|
|
692
710
|
return self._local_state.classes
|
|
693
711
|
|
|
694
712
|
@property
|
|
713
|
+
@with_deprecation_warning(
|
|
714
|
+
(2026, 8, 26),
|
|
715
|
+
"`App.registered_entrypoints` is deprecated and will be removed in `modal` version 1.6.0",
|
|
716
|
+
)
|
|
695
717
|
def registered_entrypoints(self) -> dict[str, _LocalEntrypoint]:
|
|
696
718
|
"""mdmd:hidden
|
|
697
719
|
All local CLI entrypoints registered on the app.
|
|
@@ -703,6 +725,10 @@ class _App:
|
|
|
703
725
|
return self._local_state.local_entrypoints
|
|
704
726
|
|
|
705
727
|
@property
|
|
728
|
+
@with_deprecation_warning(
|
|
729
|
+
(2026, 8, 26),
|
|
730
|
+
"`App.registered_web_endpoints` is deprecated and will be removed in `modal` version 1.6.0",
|
|
731
|
+
)
|
|
706
732
|
def registered_web_endpoints(self) -> list[str]:
|
|
707
733
|
"""mdmd:hidden
|
|
708
734
|
Names of Web Functions registered on the app.
|
|
@@ -995,7 +1021,7 @@ class _App:
|
|
|
995
1021
|
if is_generator is None:
|
|
996
1022
|
is_generator = inspect.isgeneratorfunction(raw_f) or inspect.isasyncgenfunction(raw_f)
|
|
997
1023
|
|
|
998
|
-
function = _Function.
|
|
1024
|
+
function = _Function._from_local(
|
|
999
1025
|
info,
|
|
1000
1026
|
app=self,
|
|
1001
1027
|
image=image,
|
|
@@ -1231,7 +1257,7 @@ class _App:
|
|
|
1231
1257
|
info = FunctionInfo(None, serialized=serialized, user_cls=user_cls)
|
|
1232
1258
|
|
|
1233
1259
|
i6pn_enabled = i6pn or cluster_size is not None
|
|
1234
|
-
cls_func = _Function.
|
|
1260
|
+
cls_func = _Function._from_local(
|
|
1235
1261
|
info,
|
|
1236
1262
|
app=self,
|
|
1237
1263
|
image=image or self._get_default_image(),
|
|
@@ -1274,7 +1300,7 @@ class _App:
|
|
|
1274
1300
|
|
|
1275
1301
|
self._add_function(cls_func, is_web_endpoint=False)
|
|
1276
1302
|
|
|
1277
|
-
cls: _Cls = _Cls.
|
|
1303
|
+
cls: _Cls = _Cls._from_local(user_cls, self, cls_func)
|
|
1278
1304
|
|
|
1279
1305
|
for method_name, partial_function in cls._method_partials.items():
|
|
1280
1306
|
if partial_function.params.webhook_config is not None:
|
|
@@ -1442,7 +1468,7 @@ class _App:
|
|
|
1442
1468
|
# Create the FunctionInfo for the server, note we treat FunctionInfo as a class for servers
|
|
1443
1469
|
info = FunctionInfo(None, serialized=serialized, user_cls=user_cls, name_override=name or user_cls.__name__)
|
|
1444
1470
|
# Create the service function
|
|
1445
|
-
service_function = _Function.
|
|
1471
|
+
service_function = _Function._from_local(
|
|
1446
1472
|
info,
|
|
1447
1473
|
app=self,
|
|
1448
1474
|
image=image or self._get_default_image(),
|
|
@@ -22,12 +22,16 @@ config_cli = ModalGroup(
|
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
@config_cli.command("show", help="Show current configuration values (debugging command).")
|
|
25
|
-
@click.option("--redact/--no-redact", default=True, help="Redact
|
|
25
|
+
@click.option("--redact/--no-redact", default=True, help="Redact secret credential values.")
|
|
26
26
|
def show(redact: bool):
|
|
27
27
|
# This is just a test command
|
|
28
28
|
config_dict = config.to_dict()
|
|
29
29
|
if redact and config_dict.get("token_secret"):
|
|
30
30
|
config_dict["token_secret"] = "***"
|
|
31
|
+
if redact and config_dict.get("oauth_refresh_token"):
|
|
32
|
+
config_dict["oauth_refresh_token"] = "***"
|
|
33
|
+
if redact and config_dict.get("oauth_client_secret"):
|
|
34
|
+
config_dict["oauth_client_secret"] = "***"
|
|
31
35
|
|
|
32
36
|
OutputManager.get().print_json(json.dumps(config_dict))
|
|
33
37
|
|