modal 1.5.5.dev14__tar.gz → 1.5.5.dev16__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.dev14 → modal-1.5.5.dev16}/PKG-INFO +1 -1
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_environments.py +2 -2
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_function_variants.py +2 -2
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_functions.py +33 -5
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_image.py +4 -4
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_object.py +4 -1
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_resolver.py +5 -5
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_runtime/user_code_imports.py +5 -5
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_serialization.py +7 -2
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_utils/mount_utils.py +1 -1
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_workspace.py +6 -6
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/app.py +24 -14
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/app.pyi +20 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/cli/config.py +5 -1
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/cli/import_refs.py +9 -4
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/cli/launch.py +6 -2
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/cli/run.py +10 -6
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/client.py +137 -20
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/client.pyi +124 -3
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/cls.py +21 -15
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/cls.pyi +20 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/config.py +15 -7
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/functions.pyi +82 -6
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/object.pyi +11 -30
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/runner.py +5 -5
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/sandbox.py +74 -8
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/sandbox.pyi +42 -12
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal.egg-info/PKG-INFO +1 -1
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal_proto/api_grpc.py +16 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal_proto/api_pb2.py +799 -769
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal_proto/api_pb2.pyi +124 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal_proto/api_pb2_grpc.py +33 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal_proto/api_pb2_grpc.pyi +10 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal_proto/modal_api_grpc.py +1 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal_version/__init__.py +1 -1
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/pyproject.toml +1 -1
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/LICENSE +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/README.md +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/__init__.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/__main__.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_billing.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_clustered_functions.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_clustered_functions.pyi +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_container_entrypoint.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_grpc_client.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_ipython.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_load_context.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_location.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_logs.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_logs_manager.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_logs_manager.pyi +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_output/__init__.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_output/manager.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_output/pty.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_output/rich.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_output/status.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_partial_function.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_resources.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_runtime/__init__.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_runtime/asgi.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_runtime/container_io_manager.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_runtime/container_io_manager.pyi +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_runtime/execution_context.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_runtime/execution_context.pyi +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_runtime/gpu_memory_snapshot.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_runtime/task_lifecycle_manager.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_runtime/task_lifecycle_manager.pyi +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_runtime/telemetry.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_runtime/user_code_event_loop.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_server.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_supports_logs.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_traceback.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_tunnel.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_tunnel.pyi +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_type_manager.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_utils/__init__.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_utils/app_utils.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_utils/async_utils.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_utils/auth_token_manager.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_utils/blob_utils.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_utils/browser_utils.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_utils/bytes_io_segment_payload.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_utils/curl_utils.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_utils/deprecation.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_utils/display_utils.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_utils/docker_utils.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_utils/function_utils.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_utils/git_utils.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_utils/grpc_testing.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_utils/grpc_utils.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_utils/hash_utils.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_utils/http_utils.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_utils/jwt_utils.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_utils/logger.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_utils/name_utils.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_utils/package_utils.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_utils/pattern_utils.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_utils/proxy_support.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_utils/rand_pb_testing.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_utils/sandbox_fs_utils.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_utils/shell_utils.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_utils/task_command_router_client.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_utils/time_utils.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_vendor/__init__.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_vendor/a2wsgi_wsgi.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_vendor/cloudpickle.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_vendor/tblib.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_vendor/version.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/_watcher.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/billing.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/billing.pyi +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/builder/2023.12.312.txt +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/builder/2023.12.txt +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/builder/2024.04.txt +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/builder/2024.10.txt +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/builder/2025.06.txt +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/builder/PREVIEW.txt +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/builder/README.md +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/builder/base-images.json +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/call_graph.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/cli/__init__.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/cli/_download.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/cli/_help.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/cli/_traceback.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/cli/app.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/cli/billing.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/cli/bootstrap.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/cli/changelog.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/cli/cluster.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/cli/container.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/cli/curl.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/cli/dashboard.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/cli/dict.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/cli/endpoint.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/cli/entry_point.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/cli/environment.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/cli/image.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/cli/logo.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/cli/network_file_system.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/cli/profile.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/cli/programs/__init__.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/cli/programs/run_jupyter.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/cli/programs/vscode.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/cli/queues.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/cli/secret.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/cli/selector.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/cli/shell.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/cli/skills.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/cli/token.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/cli/utils.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/cli/volume.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/cli/workspace.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/cloud_bucket_mount.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/cloud_bucket_mount.pyi +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/container_process.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/container_process.pyi +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/dict.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/dict.pyi +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/environments.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/environments.pyi +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/exception.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/experimental/__init__.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/experimental/flash.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/experimental/flash.pyi +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/experimental/ipython.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/file_io.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/file_io.pyi +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/file_pattern_matcher.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/functions.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/image.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/image.pyi +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/io_streams.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/io_streams.pyi +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/mount.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/mount.pyi +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/network_file_system.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/network_file_system.pyi +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/object.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/output.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/parallel_map.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/parallel_map.pyi +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/partial_function.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/partial_function.pyi +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/proxy.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/proxy.pyi +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/py.typed +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/queue.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/queue.pyi +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/retries.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/runner.pyi +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/running_app.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/sandbox_fs.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/sandbox_fs.pyi +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/schedule.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/scheduler_placement.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/secret.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/secret.pyi +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/server.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/server.pyi +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/serving.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/serving.pyi +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/skills/modal/SKILL.md +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/snapshot.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/snapshot.pyi +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/stream_type.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/token_flow.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/token_flow.pyi +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/types.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/volume.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/volume.pyi +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/workspace.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal/workspace.pyi +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal.egg-info/SOURCES.txt +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal.egg-info/dependency_links.txt +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal.egg-info/entry_points.txt +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal.egg-info/requires.txt +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal.egg-info/top_level.txt +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal_docs/__init__.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal_docs/gen_cli_docs.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal_docs/gen_cli_docs_main.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal_docs/gen_reference_docs.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal_docs/gen_reference_docs_main.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal_docs/mdmd/__init__.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal_docs/mdmd/mdmd.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal_docs/mdmd/signatures.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal_docs/mdmd/types.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal_docs/reference_intro.md +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal_proto/__init__.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal_proto/py.typed +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal_proto/task_command_router_grpc.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal_proto/task_command_router_pb2.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal_proto/task_command_router_pb2.pyi +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal_proto/task_command_router_pb2_grpc.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal_proto/task_command_router_pb2_grpc.pyi +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/modal_version/__main__.py +0 -0
- {modal-1.5.5.dev14 → modal-1.5.5.dev16}/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
|
|
|
@@ -663,7 +663,7 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
|
|
|
663
663
|
return _FunctionLogsManager(self)
|
|
664
664
|
|
|
665
665
|
@staticmethod
|
|
666
|
-
def
|
|
666
|
+
def _from_local(
|
|
667
667
|
info: FunctionInfo,
|
|
668
668
|
app: "modal.app._App | None", # App here should only be None in case of Image.run_function
|
|
669
669
|
image: _Image,
|
|
@@ -937,7 +937,7 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
|
|
|
937
937
|
with FunctionCreationStatus(tag) as function_creation_status:
|
|
938
938
|
timeout_secs = timeout
|
|
939
939
|
|
|
940
|
-
if app and app.
|
|
940
|
+
if app and app._is_interactive_ and not is_builder_function:
|
|
941
941
|
pty_info = get_pty_info(shell=False)
|
|
942
942
|
else:
|
|
943
943
|
pty_info = None
|
|
@@ -1164,7 +1164,9 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
|
|
|
1164
1164
|
# the only way to infer a LoadContext for an `@app.function`, and the App doesn't
|
|
1165
1165
|
# get its client until *after* the Function is created.
|
|
1166
1166
|
load_context = app._root_load_context if app else LoadContext.empty()
|
|
1167
|
-
obj = _Function._from_loader(
|
|
1167
|
+
obj: _Function = _Function._from_loader(
|
|
1168
|
+
_load, rep, preload=_preload, deps=_deps, load_context_overrides=load_context
|
|
1169
|
+
)
|
|
1168
1170
|
|
|
1169
1171
|
obj._raw_f = info.raw_f
|
|
1170
1172
|
obj._info = info
|
|
@@ -1192,6 +1194,9 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
|
|
|
1192
1194
|
|
|
1193
1195
|
return obj
|
|
1194
1196
|
|
|
1197
|
+
from_local = _from_local
|
|
1198
|
+
"""mdmd:hidden"""
|
|
1199
|
+
|
|
1195
1200
|
async def _update_autoscaler(
|
|
1196
1201
|
self,
|
|
1197
1202
|
*,
|
|
@@ -1386,6 +1391,10 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
|
|
|
1386
1391
|
@property
|
|
1387
1392
|
def tag(self) -> str:
|
|
1388
1393
|
"""mdmd:hidden"""
|
|
1394
|
+
return self._tag_
|
|
1395
|
+
|
|
1396
|
+
@property
|
|
1397
|
+
def _tag_(self) -> str:
|
|
1389
1398
|
assert self._tag
|
|
1390
1399
|
return self._tag
|
|
1391
1400
|
|
|
@@ -1406,12 +1415,20 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
|
|
|
1406
1415
|
@property
|
|
1407
1416
|
def info(self) -> FunctionInfo:
|
|
1408
1417
|
"""mdmd:hidden"""
|
|
1418
|
+
return self._info_
|
|
1419
|
+
|
|
1420
|
+
@property
|
|
1421
|
+
def _info_(self) -> FunctionInfo:
|
|
1409
1422
|
assert self._info
|
|
1410
1423
|
return self._info
|
|
1411
1424
|
|
|
1412
1425
|
@property
|
|
1413
1426
|
def spec(self) -> _FunctionSpec:
|
|
1414
1427
|
"""mdmd:hidden"""
|
|
1428
|
+
return self._spec_
|
|
1429
|
+
|
|
1430
|
+
@property
|
|
1431
|
+
def _spec_(self) -> _FunctionSpec:
|
|
1415
1432
|
assert self._spec
|
|
1416
1433
|
return self._spec
|
|
1417
1434
|
|
|
@@ -1419,13 +1436,16 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
|
|
|
1419
1436
|
# only defined in definition scope/locally, and not for class methods at the moment
|
|
1420
1437
|
return bool(self._webhook_config and self._webhook_config.type != api_pb2.WEBHOOK_TYPE_UNSPECIFIED)
|
|
1421
1438
|
|
|
1422
|
-
def
|
|
1439
|
+
def _get_build_def(self) -> str:
|
|
1423
1440
|
"""mdmd:hidden"""
|
|
1424
1441
|
# Plaintext source and arg definition for the function, so it's part of the image
|
|
1425
1442
|
# hash. We can't use the cloudpickle hash because it's not very stable.
|
|
1426
1443
|
assert hasattr(self, "_raw_f") and hasattr(self, "_build_args") and self._raw_f is not None
|
|
1427
1444
|
return f"{inspect.getsource(self._raw_f)}\n{repr(self._build_args)}"
|
|
1428
1445
|
|
|
1446
|
+
get_build_def = _get_build_def
|
|
1447
|
+
"""mdmd:hidden"""
|
|
1448
|
+
|
|
1429
1449
|
# Live handle methods
|
|
1430
1450
|
|
|
1431
1451
|
def _initialize_from_empty(self):
|
|
@@ -1675,6 +1695,10 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
|
|
|
1675
1695
|
@property
|
|
1676
1696
|
async def is_generator(self) -> bool:
|
|
1677
1697
|
"""mdmd:hidden"""
|
|
1698
|
+
return await self._is_generator_
|
|
1699
|
+
|
|
1700
|
+
@property
|
|
1701
|
+
async def _is_generator_(self) -> bool:
|
|
1678
1702
|
# hacky: kind of like @live_method, but not hydrating if we have the value already from local source
|
|
1679
1703
|
# TODO(michael) use a common / lightweight method for handling unhydrated metadata properties
|
|
1680
1704
|
if self._is_generator is not None:
|
|
@@ -1910,7 +1934,7 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
|
|
|
1910
1934
|
# TODO: check if we end up here in a container for a serialized function?
|
|
1911
1935
|
raise ExecutionError("Can't call .local on service function")
|
|
1912
1936
|
|
|
1913
|
-
if is_local() and self.
|
|
1937
|
+
if is_local() and self._spec_.volumes or self._spec_.network_file_systems:
|
|
1914
1938
|
warnings.warn(
|
|
1915
1939
|
f"The {info.function_name} function is executing locally "
|
|
1916
1940
|
+ "and will not have access to the mounted Volume or NetworkFileSystem data"
|
|
@@ -2014,6 +2038,10 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
|
|
|
2014
2038
|
Returns:
|
|
2015
2039
|
The original function object registered with Modal.
|
|
2016
2040
|
"""
|
|
2041
|
+
return self._raw_f_
|
|
2042
|
+
|
|
2043
|
+
@property
|
|
2044
|
+
def _raw_f_(self) -> Callable[..., Any]:
|
|
2017
2045
|
assert self._raw_f is not None
|
|
2018
2046
|
return self._raw_f
|
|
2019
2047
|
|
|
@@ -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
|
)
|
|
@@ -209,7 +209,7 @@ class _Object:
|
|
|
209
209
|
name: str | None = None,
|
|
210
210
|
*,
|
|
211
211
|
load_context_overrides: LoadContext,
|
|
212
|
-
):
|
|
212
|
+
) -> Self:
|
|
213
213
|
# TODO(erikbern): flip the order of the two first arguments
|
|
214
214
|
obj = _Object.__new__(cls)
|
|
215
215
|
obj._init(
|
|
@@ -313,7 +313,10 @@ class _Object:
|
|
|
313
313
|
@property
|
|
314
314
|
def deps(self) -> Callable[..., Sequence["_Object"]]:
|
|
315
315
|
"""mdmd:hidden"""
|
|
316
|
+
return self._deps_
|
|
316
317
|
|
|
318
|
+
@property
|
|
319
|
+
def _deps_(self) -> Callable[..., Sequence["_Object"]]:
|
|
317
320
|
def default_deps(*args, **kwargs) -> Sequence["_Object"]:
|
|
318
321
|
return []
|
|
319
322
|
|
|
@@ -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:
|
|
@@ -4,7 +4,7 @@ import io
|
|
|
4
4
|
import pickle
|
|
5
5
|
import typing
|
|
6
6
|
from inspect import Parameter
|
|
7
|
-
from typing import Any
|
|
7
|
+
from typing import Any, cast
|
|
8
8
|
|
|
9
9
|
from modal._traceback import extract_traceback
|
|
10
10
|
from modal.config import config
|
|
@@ -43,8 +43,11 @@ class Pickler(cloudpickle.Pickler):
|
|
|
43
43
|
|
|
44
44
|
if isinstance(obj, _Object):
|
|
45
45
|
flag = "_o"
|
|
46
|
+
is_hydrated = obj._is_hydrated
|
|
46
47
|
elif isinstance(obj, Object):
|
|
47
48
|
flag = "o"
|
|
49
|
+
inner = cast(_Object, synchronizer._translate_in(obj))
|
|
50
|
+
is_hydrated = inner._is_hydrated
|
|
48
51
|
elif isinstance(obj, PartialFunction):
|
|
49
52
|
# Special case for PartialObject since it's a synchronicity wrapped object
|
|
50
53
|
# that's set on serialized classes.
|
|
@@ -66,8 +69,10 @@ class Pickler(cloudpickle.Pickler):
|
|
|
66
69
|
return ("sync", (impl_object.__class__, attributes))
|
|
67
70
|
else:
|
|
68
71
|
return
|
|
69
|
-
|
|
72
|
+
|
|
73
|
+
if not is_hydrated:
|
|
70
74
|
raise InvalidError(f"Can't serialize object {obj} which hasn't been hydrated.")
|
|
75
|
+
|
|
71
76
|
return (obj.object_id, flag, obj._get_metadata())
|
|
72
77
|
|
|
73
78
|
|
|
@@ -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)
|
|
@@ -275,6 +275,11 @@ class _App:
|
|
|
275
275
|
|
|
276
276
|
@property
|
|
277
277
|
def is_interactive(self) -> bool:
|
|
278
|
+
"""mdmd:hidden"""
|
|
279
|
+
return self._is_interactive_
|
|
280
|
+
|
|
281
|
+
@property
|
|
282
|
+
def _is_interactive_(self) -> bool:
|
|
278
283
|
"""mdmd:hidden
|
|
279
284
|
Whether the current app for the app is running in interactive mode.
|
|
280
285
|
|
|
@@ -305,6 +310,11 @@ class _App:
|
|
|
305
310
|
"""
|
|
306
311
|
return self._description
|
|
307
312
|
|
|
313
|
+
@description.setter
|
|
314
|
+
def description(self, value):
|
|
315
|
+
"""mdmd:hidden"""
|
|
316
|
+
self._description = value
|
|
317
|
+
|
|
308
318
|
@staticmethod
|
|
309
319
|
async def lookup(
|
|
310
320
|
name: str,
|
|
@@ -379,7 +389,7 @@ class _App:
|
|
|
379
389
|
|
|
380
390
|
Note: we don't recommend using the method and may deprecate it in the future.
|
|
381
391
|
"""
|
|
382
|
-
self.
|
|
392
|
+
self.description = description
|
|
383
393
|
|
|
384
394
|
def _validate_blueprint_value(self, key: str, value: Any):
|
|
385
395
|
if not isinstance(value, _Object):
|
|
@@ -589,14 +599,14 @@ class _App:
|
|
|
589
599
|
raise ExecutionError("`_get_watch_mounts` requires a running app.")
|
|
590
600
|
|
|
591
601
|
all_mounts = []
|
|
592
|
-
for function in self.
|
|
602
|
+
for function in self._local_state.functions.values():
|
|
593
603
|
all_mounts.extend(function._serve_mounts)
|
|
594
604
|
|
|
595
605
|
return [m for m in all_mounts if m.is_local()]
|
|
596
606
|
|
|
597
607
|
def _add_function(self, function: _Function, is_web_endpoint: bool):
|
|
598
608
|
local_state = self._local_state
|
|
599
|
-
if old_function := local_state.functions.get(function.
|
|
609
|
+
if old_function := local_state.functions.get(function._tag_, None):
|
|
600
610
|
if old_function is function:
|
|
601
611
|
return # already added the same exact instance, ignore
|
|
602
612
|
|
|
@@ -605,25 +615,25 @@ class _App:
|
|
|
605
615
|
# and we don't want to warn about a collision in that case.
|
|
606
616
|
if not is_interactive_ipython():
|
|
607
617
|
logger.warning(
|
|
608
|
-
f"Warning: function name '{function.
|
|
618
|
+
f"Warning: function name '{function._tag_}' collision!"
|
|
609
619
|
" Overriding existing function "
|
|
610
620
|
f"[{old_function._info.module_name}].{old_function._info.function_name}"
|
|
611
621
|
f" with new function [{function._info.module_name}].{function._info.function_name}"
|
|
612
622
|
)
|
|
613
|
-
if function.
|
|
614
|
-
logger.warning(f"Warning: tag {function.
|
|
623
|
+
if function._tag_ in local_state.classes:
|
|
624
|
+
logger.warning(f"Warning: tag {function._tag_} exists but is overridden by function")
|
|
615
625
|
|
|
616
626
|
if self._running_app:
|
|
617
627
|
# If this is inside a container, then objects can be defined after app initialization.
|
|
618
628
|
# So we may have to initialize objects once they get bound to the app.
|
|
619
|
-
if function.
|
|
620
|
-
object_id: str = self._running_app.function_ids[function.
|
|
629
|
+
if function._tag_ in self._running_app.function_ids:
|
|
630
|
+
object_id: str = self._running_app.function_ids[function._tag_]
|
|
621
631
|
metadata: Message = self._running_app.object_handle_metadata[object_id]
|
|
622
632
|
function._hydrate(object_id, self._client, metadata)
|
|
623
633
|
|
|
624
|
-
local_state.functions[function.
|
|
634
|
+
local_state.functions[function._tag_] = function
|
|
625
635
|
if is_web_endpoint:
|
|
626
|
-
local_state.web_endpoints.append(function.
|
|
636
|
+
local_state.web_endpoints.append(function._tag_)
|
|
627
637
|
|
|
628
638
|
def _add_class(self, tag: str, cls: _Cls):
|
|
629
639
|
if self._running_app:
|
|
@@ -985,7 +995,7 @@ class _App:
|
|
|
985
995
|
if is_generator is None:
|
|
986
996
|
is_generator = inspect.isgeneratorfunction(raw_f) or inspect.isasyncgenfunction(raw_f)
|
|
987
997
|
|
|
988
|
-
function = _Function.
|
|
998
|
+
function = _Function._from_local(
|
|
989
999
|
info,
|
|
990
1000
|
app=self,
|
|
991
1001
|
image=image,
|
|
@@ -1221,7 +1231,7 @@ class _App:
|
|
|
1221
1231
|
info = FunctionInfo(None, serialized=serialized, user_cls=user_cls)
|
|
1222
1232
|
|
|
1223
1233
|
i6pn_enabled = i6pn or cluster_size is not None
|
|
1224
|
-
cls_func = _Function.
|
|
1234
|
+
cls_func = _Function._from_local(
|
|
1225
1235
|
info,
|
|
1226
1236
|
app=self,
|
|
1227
1237
|
image=image or self._get_default_image(),
|
|
@@ -1264,7 +1274,7 @@ class _App:
|
|
|
1264
1274
|
|
|
1265
1275
|
self._add_function(cls_func, is_web_endpoint=False)
|
|
1266
1276
|
|
|
1267
|
-
cls: _Cls = _Cls.
|
|
1277
|
+
cls: _Cls = _Cls._from_local(user_cls, self, cls_func)
|
|
1268
1278
|
|
|
1269
1279
|
for method_name, partial_function in cls._method_partials.items():
|
|
1270
1280
|
if partial_function.params.webhook_config is not None:
|
|
@@ -1432,7 +1442,7 @@ class _App:
|
|
|
1432
1442
|
# Create the FunctionInfo for the server, note we treat FunctionInfo as a class for servers
|
|
1433
1443
|
info = FunctionInfo(None, serialized=serialized, user_cls=user_cls, name_override=name or user_cls.__name__)
|
|
1434
1444
|
# Create the service function
|
|
1435
|
-
service_function = _Function.
|
|
1445
|
+
service_function = _Function._from_local(
|
|
1436
1446
|
info,
|
|
1437
1447
|
app=self,
|
|
1438
1448
|
image=image or self._get_default_image(),
|
|
@@ -205,6 +205,11 @@ class _App:
|
|
|
205
205
|
|
|
206
206
|
@property
|
|
207
207
|
def is_interactive(self) -> bool:
|
|
208
|
+
"""mdmd:hidden"""
|
|
209
|
+
...
|
|
210
|
+
|
|
211
|
+
@property
|
|
212
|
+
def _is_interactive_(self) -> bool:
|
|
208
213
|
"""mdmd:hidden
|
|
209
214
|
Whether the current app for the app is running in interactive mode.
|
|
210
215
|
|
|
@@ -230,6 +235,11 @@ class _App:
|
|
|
230
235
|
"""
|
|
231
236
|
...
|
|
232
237
|
|
|
238
|
+
@description.setter
|
|
239
|
+
def description(self, value):
|
|
240
|
+
"""mdmd:hidden"""
|
|
241
|
+
...
|
|
242
|
+
|
|
233
243
|
@staticmethod
|
|
234
244
|
async def lookup(
|
|
235
245
|
name: str,
|
|
@@ -1023,6 +1033,11 @@ class App:
|
|
|
1023
1033
|
|
|
1024
1034
|
@property
|
|
1025
1035
|
def is_interactive(self) -> bool:
|
|
1036
|
+
"""mdmd:hidden"""
|
|
1037
|
+
...
|
|
1038
|
+
|
|
1039
|
+
@property
|
|
1040
|
+
def _is_interactive_(self) -> bool:
|
|
1026
1041
|
"""mdmd:hidden
|
|
1027
1042
|
Whether the current app for the app is running in interactive mode.
|
|
1028
1043
|
|
|
@@ -1048,6 +1063,11 @@ class App:
|
|
|
1048
1063
|
"""
|
|
1049
1064
|
...
|
|
1050
1065
|
|
|
1066
|
+
@description.setter
|
|
1067
|
+
def description(self, value):
|
|
1068
|
+
"""mdmd:hidden"""
|
|
1069
|
+
...
|
|
1070
|
+
|
|
1051
1071
|
class __lookup_spec(typing_extensions.Protocol):
|
|
1052
1072
|
def __call__(
|
|
1053
1073
|
self,
|
|
@@ -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
|
|
|
@@ -27,6 +27,8 @@ from modal.exception import InvalidError, _CliUserExecutionError
|
|
|
27
27
|
from modal.functions import Function
|
|
28
28
|
from modal.output import OutputManager
|
|
29
29
|
|
|
30
|
+
from .._utils.async_utils import synchronizer
|
|
31
|
+
|
|
30
32
|
|
|
31
33
|
@dataclasses.dataclass
|
|
32
34
|
class ImportRef:
|
|
@@ -165,15 +167,18 @@ def list_cli_commands(
|
|
|
165
167
|
all_runnables: dict[Runnable, list[str]] = defaultdict(list)
|
|
166
168
|
priorities: dict[Runnable, int] = defaultdict(lambda: AutoRunPriority.APP_FUNCTION)
|
|
167
169
|
for app_name, app in apps:
|
|
168
|
-
for name,
|
|
170
|
+
for name, inner_entrypoint in app._local_state.local_entrypoints.items():
|
|
171
|
+
local_entrypoint = cast(LocalEntrypoint, synchronizer._translate_out(inner_entrypoint))
|
|
169
172
|
all_runnables[local_entrypoint].append(f"{app_name}.{name}")
|
|
170
173
|
priorities[local_entrypoint] = AutoRunPriority.APP_LOCAL_ENTRYPOINT
|
|
171
|
-
for name,
|
|
172
|
-
|
|
174
|
+
for name, inner_function in app._local_state.functions.items():
|
|
175
|
+
function = cast(Function, synchronizer._translate_out(inner_function))
|
|
176
|
+
if function._info_.is_service_class() and not include_service_functions:
|
|
173
177
|
continue # Skip class and server service functions for all commands except `modal shell`.
|
|
174
178
|
all_runnables[function].append(f"{app_name}.{name}")
|
|
175
179
|
priorities[function] = AutoRunPriority.APP_FUNCTION
|
|
176
|
-
for cls_name,
|
|
180
|
+
for cls_name, inner_cls in app._local_state.classes.items():
|
|
181
|
+
cls = cast(Cls, synchronizer._translate_out(inner_cls))
|
|
177
182
|
for method_name in cls._get_method_names():
|
|
178
183
|
method_ref = MethodReference(cls, method_name)
|
|
179
184
|
all_runnables[method_ref].append(f"{app_name}.{cls_name}.{method_name}")
|
|
@@ -4,12 +4,15 @@ import inspect
|
|
|
4
4
|
import json
|
|
5
5
|
import os
|
|
6
6
|
from pathlib import Path
|
|
7
|
-
from typing import Any
|
|
7
|
+
from typing import Any, cast
|
|
8
8
|
|
|
9
9
|
import click
|
|
10
10
|
import rich.panel
|
|
11
11
|
from rich.markdown import Markdown
|
|
12
12
|
|
|
13
|
+
from modal.app import _App
|
|
14
|
+
|
|
15
|
+
from .._utils.async_utils import synchronizer
|
|
13
16
|
from ..exception import _CliUserExecutionError
|
|
14
17
|
from ..output import OutputManager
|
|
15
18
|
from ..runner import run_app
|
|
@@ -40,7 +43,8 @@ def _launch_program(
|
|
|
40
43
|
entrypoint = module.main
|
|
41
44
|
|
|
42
45
|
app = _get_runnable_app(entrypoint)
|
|
43
|
-
|
|
46
|
+
inner = cast(_App, synchronizer._translate_in(app))
|
|
47
|
+
inner._description = description if description else base_cmd
|
|
44
48
|
|
|
45
49
|
# `launch/` scripts must have a `local_entrypoint()` with no args, for simplicity here.
|
|
46
50
|
func = entrypoint.info.raw_f
|