modal 1.6.4.dev2__tar.gz → 1.6.4.dev3__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.6.4.dev2 → modal-1.6.4.dev3}/PKG-INFO +1 -1
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_runtime/task_lifecycle_manager.py +23 -2
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_runtime/task_lifecycle_manager.pyi +6 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/cli/image.py +119 -1
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/client.pyi +2 -2
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/config.py +5 -7
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/functions.pyi +6 -6
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/runner.py +10 -7
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/runner.pyi +5 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal.egg-info/PKG-INFO +1 -1
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal_proto/api_pb2.py +1398 -1398
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal_proto/api_pb2.pyi +4 -1
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal_version/__init__.py +1 -1
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/pyproject.toml +0 -1
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/LICENSE +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/README.md +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/__init__.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/__main__.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_billing.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_cluster.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_cluster.pyi +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_container_entrypoint.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_environments.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_function_variants.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_functions.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_grpc_client.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_image.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_ipython.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_load_context.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_location.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_logs.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_logs_manager.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_logs_manager.pyi +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_metrics.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_metrics.pyi +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_object.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_outbound_policy.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_outbound_policy.pyi +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_output/__init__.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_output/manager.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_output/pty.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_output/rich.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_output/status.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_partial_function.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_resolver.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_resources.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_runtime/__init__.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_runtime/asgi.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_runtime/container_io_manager.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_runtime/container_io_manager.pyi +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_runtime/execution_context.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_runtime/execution_context.pyi +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_runtime/gpu_memory_snapshot.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_runtime/telemetry.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_runtime/user_code_event_loop.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_runtime/user_code_imports.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_serialization.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_server.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_server.pyi +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_supports_logs.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_traceback.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_tunnel.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_tunnel.pyi +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_type_manager.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_utils/__init__.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_utils/app_utils.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_utils/async_utils.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_utils/auth_token_manager.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_utils/blob_utils.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_utils/browser_utils.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_utils/bytes_io_segment_payload.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_utils/curl_utils.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_utils/deprecation.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_utils/display_utils.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_utils/docker_utils.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_utils/function_utils.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_utils/git_utils.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_utils/grpc_testing.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_utils/grpc_utils.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_utils/hash_utils.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_utils/http_utils.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_utils/idle_countdown.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_utils/jwt_utils.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_utils/logger.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_utils/mount_utils.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_utils/name_utils.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_utils/oauth.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_utils/package_utils.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_utils/pattern_utils.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_utils/proxy_support.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_utils/rand_pb_testing.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_utils/sandbox_fs_utils.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_utils/shell_utils.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_utils/time_utils.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_vendor/__init__.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_vendor/a2wsgi_wsgi.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_vendor/cloudpickle.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_vendor/tblib.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_vendor/version.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_watcher.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/_workspace.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/app.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/app.pyi +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/billing.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/billing.pyi +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/builder/2023.12.312.txt +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/builder/2023.12.txt +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/builder/2024.04.txt +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/builder/2024.10.txt +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/builder/2025.06.txt +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/builder/2026.10.txt +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/builder/PREVIEW.txt +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/builder/README.md +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/builder/base-images.json +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/call_graph.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/cli/__init__.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/cli/_download.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/cli/_help.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/cli/_logs.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/cli/_stats.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/cli/_traceback.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/cli/app.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/cli/billing.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/cli/changelog.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/cli/config.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/cli/container.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/cli/curl.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/cli/dashboard.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/cli/dict.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/cli/endpoint.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/cli/entry_point.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/cli/environment.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/cli/function.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/cli/import_refs.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/cli/logo.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/cli/network_file_system.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/cli/profile.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/cli/queues.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/cli/run.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/cli/secret.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/cli/selector.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/cli/server.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/cli/shell.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/cli/skills.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/cli/token.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/cli/utils.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/cli/volume.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/cli/workspace.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/client.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/cloud_bucket_mount.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/cloud_bucket_mount.pyi +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/cls.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/cls.pyi +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/cluster.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/cluster.pyi +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/container_process.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/container_process.pyi +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/dict.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/dict.pyi +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/environments.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/environments.pyi +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/exception.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/experimental/__init__.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/experimental/_flash_container_entry.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/experimental/flash.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/experimental/flash.pyi +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/experimental/flash_server.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/experimental/flash_server.pyi +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/experimental/ipython.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/file_pattern_matcher.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/functions.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/image.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/image.pyi +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/io_streams.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/io_streams.pyi +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/mount.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/mount.pyi +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/network_file_system.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/network_file_system.pyi +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/object.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/object.pyi +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/output.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/parallel_map.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/parallel_map.pyi +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/partial_function.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/partial_function.pyi +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/proxy.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/proxy.pyi +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/py.typed +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/queue.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/queue.pyi +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/retries.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/running_app.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/sandbox/__init__.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/sandbox/_common.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/sandbox/_filesystem.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/sandbox/_impl_persistent.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/sandbox/_impl_v1.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/sandbox/_impl_v2.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/sandbox/_sandbox.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/sandbox/_sidecar.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/sandbox/_snapshot.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/sandbox/_task_command_router_client.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/sandbox/sandbox.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/sandbox/sandbox.pyi +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/schedule.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/scheduler_placement.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/secret.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/secret.pyi +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/server.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/server.pyi +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/serving.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/serving.pyi +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/skills/modal/SKILL.md +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/stream_type.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/token_flow.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/token_flow.pyi +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/types.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/volume.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/volume.pyi +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/workspace.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal/workspace.pyi +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal.egg-info/SOURCES.txt +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal.egg-info/dependency_links.txt +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal.egg-info/entry_points.txt +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal.egg-info/requires.txt +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal.egg-info/top_level.txt +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal_docs/__init__.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal_docs/gen_cli_docs.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal_docs/gen_cli_docs_main.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal_docs/gen_reference_docs.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal_docs/gen_reference_docs_main.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal_docs/mdmd/__init__.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal_docs/mdmd/mdmd.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal_docs/mdmd/signatures.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal_docs/mdmd/types.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal_docs/reference_intro.md +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal_proto/__init__.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal_proto/api_grpc.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal_proto/api_pb2_grpc.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal_proto/api_pb2_grpc.pyi +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal_proto/modal_api_grpc.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal_proto/py.typed +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal_proto/task_command_router_grpc.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal_proto/task_command_router_pb2.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal_proto/task_command_router_pb2.pyi +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal_proto/task_command_router_pb2_grpc.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal_proto/task_command_router_pb2_grpc.pyi +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/modal_version/__main__.py +0 -0
- {modal-1.6.4.dev2 → modal-1.6.4.dev3}/setup.cfg +0 -0
|
@@ -25,9 +25,19 @@ from modal._utils.blob_utils import format_blob_data
|
|
|
25
25
|
from modal._utils.grpc_utils import Retry
|
|
26
26
|
from modal._utils.package_utils import parse_major_minor_version
|
|
27
27
|
from modal.client import _Client
|
|
28
|
-
from modal.config import config, logger
|
|
28
|
+
from modal.config import _env_var_name, config, logger
|
|
29
29
|
from modal_proto import api_pb2
|
|
30
30
|
|
|
31
|
+
SPEC_ENVIRON_PATH: str = "/proc/gvisor/spec_environ"
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _read_spec_environ() -> dict[str, str]:
|
|
35
|
+
path = Path(SPEC_ENVIRON_PATH)
|
|
36
|
+
if not path.exists():
|
|
37
|
+
return {}
|
|
38
|
+
entries = (entry.partition("=") for entry in path.read_text("utf8").split("\0"))
|
|
39
|
+
return {key: value for key, sep, value in entries if sep}
|
|
40
|
+
|
|
31
41
|
|
|
32
42
|
class UserException(Exception):
|
|
33
43
|
"""Used to shut down the task gracefully."""
|
|
@@ -42,6 +52,7 @@ class _TaskLifecycleManager:
|
|
|
42
52
|
checkpoint_id: str | None
|
|
43
53
|
_client: _Client
|
|
44
54
|
_cuda_checkpoint_session: gpu_memory_snapshot.CudaCheckpointSession | None
|
|
55
|
+
_snapshot_spec_environ: dict[str, str]
|
|
45
56
|
|
|
46
57
|
def _init(
|
|
47
58
|
self,
|
|
@@ -57,6 +68,7 @@ class _TaskLifecycleManager:
|
|
|
57
68
|
self.checkpoint_id = checkpoint_id
|
|
58
69
|
self._client = client
|
|
59
70
|
self._cuda_checkpoint_session = None
|
|
71
|
+
self._snapshot_spec_environ = {}
|
|
60
72
|
|
|
61
73
|
def __new__(
|
|
62
74
|
cls,
|
|
@@ -171,10 +183,18 @@ class _TaskLifecycleManager:
|
|
|
171
183
|
setattr(self, key, restored_state[key])
|
|
172
184
|
|
|
173
185
|
# Env vars and global state.
|
|
186
|
+
env_updates = {}
|
|
187
|
+
for key, value in _read_spec_environ().items():
|
|
188
|
+
if self._snapshot_spec_environ.get(key) != value:
|
|
189
|
+
env_updates[key] = value
|
|
190
|
+
|
|
191
|
+
# Values from the restore state take precedence.
|
|
174
192
|
for key, value in restored_state.items():
|
|
175
193
|
# Empty string indicates that value does not need to be updated.
|
|
176
194
|
if value != "":
|
|
177
|
-
|
|
195
|
+
env_updates[_env_var_name(key)] = value
|
|
196
|
+
|
|
197
|
+
os.environ.update(env_updates)
|
|
178
198
|
|
|
179
199
|
# Restore GPU memory.
|
|
180
200
|
if self.function_def._experimental_enable_gpu_snapshot and self.function_def.resources.gpu_config.gpu_type:
|
|
@@ -205,6 +225,7 @@ class _TaskLifecycleManager:
|
|
|
205
225
|
self._cuda_checkpoint_session = gpu_memory_snapshot.CudaCheckpointSession()
|
|
206
226
|
self._cuda_checkpoint_session.checkpoint()
|
|
207
227
|
|
|
228
|
+
self._snapshot_spec_environ = _read_spec_environ()
|
|
208
229
|
await self._client._stub.ContainerCheckpoint(
|
|
209
230
|
api_pb2.ContainerCheckpointRequest(checkpoint_id=self.checkpoint_id)
|
|
210
231
|
)
|
|
@@ -5,6 +5,8 @@ import synchronicity.combined_types
|
|
|
5
5
|
import typing
|
|
6
6
|
import typing_extensions
|
|
7
7
|
|
|
8
|
+
def _read_spec_environ() -> dict[str, str]: ...
|
|
9
|
+
|
|
8
10
|
class UserException(Exception):
|
|
9
11
|
"""Used to shut down the task gracefully."""
|
|
10
12
|
|
|
@@ -18,6 +20,7 @@ class _TaskLifecycleManager:
|
|
|
18
20
|
checkpoint_id: typing.Optional[str]
|
|
19
21
|
_client: modal.client._Client
|
|
20
22
|
_cuda_checkpoint_session: typing.Optional[modal._runtime.gpu_memory_snapshot.CudaCheckpointSession]
|
|
23
|
+
_snapshot_spec_environ: dict[str, str]
|
|
21
24
|
|
|
22
25
|
def _init(
|
|
23
26
|
self,
|
|
@@ -67,6 +70,7 @@ class TaskLifecycleManager:
|
|
|
67
70
|
checkpoint_id: typing.Optional[str]
|
|
68
71
|
_client: modal.client.Client
|
|
69
72
|
_cuda_checkpoint_session: typing.Optional[modal._runtime.gpu_memory_snapshot.CudaCheckpointSession]
|
|
73
|
+
_snapshot_spec_environ: dict[str, str]
|
|
70
74
|
|
|
71
75
|
def __init__(self, /, *args, **kwargs):
|
|
72
76
|
"""Initialize self. See help(type(self)) for accurate signature."""
|
|
@@ -136,3 +140,5 @@ def check_fastapi_pydantic_compatibility(exc: ImportError) -> None:
|
|
|
136
140
|
building an image that specifies a more recent version only for pydantic.
|
|
137
141
|
"""
|
|
138
142
|
...
|
|
143
|
+
|
|
144
|
+
SPEC_ENVIRON_PATH: str
|
|
@@ -4,21 +4,27 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import asyncio
|
|
6
6
|
import json as json_module
|
|
7
|
+
import os
|
|
7
8
|
from collections.abc import AsyncIterator
|
|
8
9
|
from typing import Optional
|
|
9
10
|
|
|
10
11
|
import click
|
|
12
|
+
from rich.syntax import Syntax
|
|
11
13
|
|
|
12
14
|
from modal._environments import ensure_env
|
|
13
|
-
from modal._image import _upgrade_image_name
|
|
15
|
+
from modal._image import _Image, _infer_registry_auth_type, _upgrade_image_name
|
|
14
16
|
from modal._logs_manager import _resolve_source
|
|
15
17
|
from modal._utils.async_utils import synchronizer
|
|
16
18
|
from modal._utils.time_utils import timestamp_to_localized_str
|
|
19
|
+
from modal.app import _App
|
|
17
20
|
from modal.cli.utils import display_table, env_option
|
|
18
21
|
from modal.client import _Client
|
|
19
22
|
from modal.config import config
|
|
23
|
+
from modal.exception import InvalidError
|
|
20
24
|
from modal.image import Image
|
|
21
25
|
from modal.output import OutputManager
|
|
26
|
+
from modal.runner import _run_app
|
|
27
|
+
from modal.secret import _Secret
|
|
22
28
|
from modal_proto import api_pb2
|
|
23
29
|
|
|
24
30
|
from ._help import ModalGroup
|
|
@@ -36,6 +42,118 @@ def _print_result_summary(count: int) -> None:
|
|
|
36
42
|
OutputManager.get().print(f"Showing {count} {result_label}")
|
|
37
43
|
|
|
38
44
|
|
|
45
|
+
async def _registry_secret(
|
|
46
|
+
secret_name: Optional[str], secret_vars: Optional[str], env: str
|
|
47
|
+
) -> tuple[Optional[_Secret], set[str]]:
|
|
48
|
+
if secret_name and secret_vars:
|
|
49
|
+
raise click.UsageError("--registry-secret and --registry-secret-from-env cannot be used together.")
|
|
50
|
+
if secret_name:
|
|
51
|
+
secret = _Secret.from_name(secret_name, environment_name=env)
|
|
52
|
+
return secret, await secret._get_keys()
|
|
53
|
+
keys = [key.strip() for key in (secret_vars or "").split(",") if key.strip()]
|
|
54
|
+
if not keys:
|
|
55
|
+
return None, set()
|
|
56
|
+
return _Secret.from_local_environ(keys), set(keys)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
@image_cli.command("build", no_args_is_help=True)
|
|
60
|
+
@click.argument("context_dir", metavar="CONTEXT_DIR")
|
|
61
|
+
@click.option(
|
|
62
|
+
"-t",
|
|
63
|
+
"--name",
|
|
64
|
+
"name",
|
|
65
|
+
metavar="[ENV/]NAME[:TAG]",
|
|
66
|
+
required=True,
|
|
67
|
+
help="Name to publish the Image as, e.g. `my-image`, `my-image:v2`, or `my-env/my-image`.",
|
|
68
|
+
)
|
|
69
|
+
@click.option(
|
|
70
|
+
"-f",
|
|
71
|
+
"--file",
|
|
72
|
+
"dockerfile",
|
|
73
|
+
type=click.Path(exists=True, dir_okay=False),
|
|
74
|
+
default=None,
|
|
75
|
+
help="Path to the Dockerfile. Defaults to `CONTEXT_DIR/Dockerfile`.",
|
|
76
|
+
)
|
|
77
|
+
@click.option(
|
|
78
|
+
"--registry-secret",
|
|
79
|
+
"registry_secret_name",
|
|
80
|
+
metavar="SECRET_NAME",
|
|
81
|
+
default=None,
|
|
82
|
+
help="Name of a Secret with credentials for pulling the base image from a private registry.",
|
|
83
|
+
)
|
|
84
|
+
@click.option(
|
|
85
|
+
"--registry-secret-from-env",
|
|
86
|
+
"registry_secret_vars",
|
|
87
|
+
default=None,
|
|
88
|
+
metavar="VAR[,VAR...]",
|
|
89
|
+
help=(
|
|
90
|
+
"Comma-separated local environment variable names holding registry credentials. "
|
|
91
|
+
"Cannot be combined with --registry-secret."
|
|
92
|
+
),
|
|
93
|
+
)
|
|
94
|
+
@click.option("--force-build", is_flag=True, help="Rebuild every layer of the Image, ignoring cached builds.")
|
|
95
|
+
@env_option
|
|
96
|
+
@synchronizer.create_blocking
|
|
97
|
+
async def build(
|
|
98
|
+
context_dir: str,
|
|
99
|
+
name: str,
|
|
100
|
+
dockerfile: Optional[str],
|
|
101
|
+
registry_secret_name: Optional[str],
|
|
102
|
+
registry_secret_vars: Optional[str],
|
|
103
|
+
force_build: bool,
|
|
104
|
+
env: Optional[str],
|
|
105
|
+
) -> None:
|
|
106
|
+
"""Build an Image from a Dockerfile and publish it as NAME.
|
|
107
|
+
|
|
108
|
+
CONTEXT_DIR is the build context used to resolve relative COPY paths. Use `.` for the current directory.
|
|
109
|
+
|
|
110
|
+
NAME defaults to the `latest` tag. `--env` sets the environment the build runs in and where
|
|
111
|
+
`--registry-secret` is looked up. The Image is published into that environment unless NAME has an
|
|
112
|
+
environment prefix, e.g. `my-env/my-image`.
|
|
113
|
+
|
|
114
|
+
Examples:
|
|
115
|
+
|
|
116
|
+
```
|
|
117
|
+
modal image build -t my-image .
|
|
118
|
+
modal image build --name my-image:v2 -f docker/Dockerfile .
|
|
119
|
+
modal image build -t my-env/my-image .
|
|
120
|
+
modal image build -t my-image --registry-secret my-registry-creds .
|
|
121
|
+
modal image build -t my-image --registry-secret-from-env REGISTRY_USERNAME,REGISTRY_PASSWORD .
|
|
122
|
+
```
|
|
123
|
+
"""
|
|
124
|
+
if not os.path.isdir(context_dir):
|
|
125
|
+
raise click.UsageError(f"CONTEXT_DIR {context_dir!r} is not a directory.")
|
|
126
|
+
if dockerfile is None:
|
|
127
|
+
dockerfile = os.path.join(context_dir, "Dockerfile")
|
|
128
|
+
if not os.path.isfile(dockerfile):
|
|
129
|
+
raise click.UsageError(f"No Dockerfile found at {dockerfile}. Use --file to specify one.")
|
|
130
|
+
env = ensure_env(env)
|
|
131
|
+
try:
|
|
132
|
+
tag = _upgrade_image_name(name, fallback_environment_name=env)
|
|
133
|
+
except InvalidError as exc:
|
|
134
|
+
raise click.UsageError(str(exc))
|
|
135
|
+
|
|
136
|
+
secret, keys = await _registry_secret(registry_secret_name, registry_secret_vars, env)
|
|
137
|
+
if secret is not None:
|
|
138
|
+
# Fail before creating the app; from_dockerfile runs the same check during the build
|
|
139
|
+
try:
|
|
140
|
+
_infer_registry_auth_type(keys)
|
|
141
|
+
except InvalidError as exc:
|
|
142
|
+
raise click.UsageError(str(exc)) from exc
|
|
143
|
+
image = _Image.from_dockerfile(dockerfile, context_dir=context_dir, registry_secret=secret, force_build=force_build)
|
|
144
|
+
app = _App("modal-image-build")
|
|
145
|
+
# Only show the Image build output, which includes its logs
|
|
146
|
+
async with _run_app(app, environment_name=env, stream_output=False):
|
|
147
|
+
await image.build(app)
|
|
148
|
+
await image.publish(tag)
|
|
149
|
+
|
|
150
|
+
output_mgr = OutputManager.get()
|
|
151
|
+
output_mgr.step_completed(f"Image built: [bold]{image.object_id}[/bold]")
|
|
152
|
+
output_mgr.step_completed(f"Image published as [bold magenta]{tag}[/bold magenta]! 🎉")
|
|
153
|
+
output_mgr.print("\nUse it with:\n")
|
|
154
|
+
output_mgr.print(Syntax(f'modal.Image.from_name("{tag}")', "python"))
|
|
155
|
+
|
|
156
|
+
|
|
39
157
|
@image_cli.command("logs", no_args_is_help=True)
|
|
40
158
|
@click.argument("image_id")
|
|
41
159
|
@click.option(
|
|
@@ -87,7 +87,7 @@ class _Client:
|
|
|
87
87
|
server_url: str,
|
|
88
88
|
client_type: int,
|
|
89
89
|
credentials: typing.Optional[tuple[str, str]],
|
|
90
|
-
version: str = "1.6.4.
|
|
90
|
+
version: str = "1.6.4.dev3",
|
|
91
91
|
*,
|
|
92
92
|
oauth_credentials: typing.Optional[_OAuthCredentials] = None,
|
|
93
93
|
):
|
|
@@ -304,7 +304,7 @@ class Client:
|
|
|
304
304
|
server_url: str,
|
|
305
305
|
client_type: int,
|
|
306
306
|
credentials: typing.Optional[tuple[str, str]],
|
|
307
|
-
version: str = "1.6.4.
|
|
307
|
+
version: str = "1.6.4.dev3",
|
|
308
308
|
*,
|
|
309
309
|
oauth_credentials: typing.Optional[_OAuthCredentials] = None,
|
|
310
310
|
):
|
|
@@ -414,6 +414,10 @@ _SETTINGS = {
|
|
|
414
414
|
}
|
|
415
415
|
|
|
416
416
|
|
|
417
|
+
def _env_var_name(key: str) -> str:
|
|
418
|
+
return f"MODAL_{key.upper()}" if key in _SETTINGS else key.upper()
|
|
419
|
+
|
|
420
|
+
|
|
417
421
|
class Config:
|
|
418
422
|
"""Singleton that holds configuration used by Modal internally."""
|
|
419
423
|
|
|
@@ -474,13 +478,7 @@ class Config:
|
|
|
474
478
|
# Override setting in this process by overriding environment variable for the setting
|
|
475
479
|
#
|
|
476
480
|
# Does NOT write back to settings file etc.
|
|
477
|
-
|
|
478
|
-
self.get(key)
|
|
479
|
-
os.environ["MODAL_" + key.upper()] = value
|
|
480
|
-
except KeyError:
|
|
481
|
-
# Override env vars not available in config, e.g. NVIDIA_VISIBLE_DEVICES.
|
|
482
|
-
# This is used for restoring env vars from a memory snapshot.
|
|
483
|
-
os.environ[key.upper()] = value
|
|
481
|
+
os.environ[_env_var_name(key)] = value
|
|
484
482
|
|
|
485
483
|
def __getitem__(self, key):
|
|
486
484
|
return self.get(key)
|
|
@@ -619,7 +619,7 @@ class Function(
|
|
|
619
619
|
|
|
620
620
|
_call_generator: ___call_generator_spec
|
|
621
621
|
|
|
622
|
-
class __remote_spec(typing_extensions.Protocol[
|
|
622
|
+
class __remote_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER]):
|
|
623
623
|
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> ReturnType_INNER:
|
|
624
624
|
"""Calls the function remotely, executing it with the given arguments and returning the execution's result.
|
|
625
625
|
|
|
@@ -644,7 +644,7 @@ class Function(
|
|
|
644
644
|
"""
|
|
645
645
|
...
|
|
646
646
|
|
|
647
|
-
remote: __remote_spec[modal._functions.
|
|
647
|
+
remote: __remote_spec[modal._functions.P, modal._functions.ReturnType]
|
|
648
648
|
|
|
649
649
|
class __remote_gen_spec(typing_extensions.Protocol):
|
|
650
650
|
def __call__(self, /, *args, **kwargs) -> typing.Generator[typing.Any, None, None]:
|
|
@@ -694,7 +694,7 @@ class Function(
|
|
|
694
694
|
"""
|
|
695
695
|
...
|
|
696
696
|
|
|
697
|
-
class ___experimental_spawn_spec(typing_extensions.Protocol[
|
|
697
|
+
class ___experimental_spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER]):
|
|
698
698
|
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
|
|
699
699
|
"""[Experimental] Calls the function with the given arguments, without waiting for the results.
|
|
700
700
|
|
|
@@ -727,7 +727,7 @@ class Function(
|
|
|
727
727
|
"""
|
|
728
728
|
...
|
|
729
729
|
|
|
730
|
-
_experimental_spawn: ___experimental_spawn_spec[modal._functions.
|
|
730
|
+
_experimental_spawn: ___experimental_spawn_spec[modal._functions.P, modal._functions.ReturnType]
|
|
731
731
|
|
|
732
732
|
class ___spawn_map_inner_spec(typing_extensions.Protocol[P_INNER]):
|
|
733
733
|
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> None: ...
|
|
@@ -735,7 +735,7 @@ class Function(
|
|
|
735
735
|
|
|
736
736
|
_spawn_map_inner: ___spawn_map_inner_spec[modal._functions.P]
|
|
737
737
|
|
|
738
|
-
class __spawn_spec(typing_extensions.Protocol[
|
|
738
|
+
class __spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER]):
|
|
739
739
|
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
|
|
740
740
|
"""Calls the function with the given arguments, without waiting for the results.
|
|
741
741
|
|
|
@@ -768,7 +768,7 @@ class Function(
|
|
|
768
768
|
"""
|
|
769
769
|
...
|
|
770
770
|
|
|
771
|
-
spawn: __spawn_spec[modal._functions.
|
|
771
|
+
spawn: __spawn_spec[modal._functions.P, modal._functions.ReturnType]
|
|
772
772
|
|
|
773
773
|
@property
|
|
774
774
|
def _raw_f_(self) -> collections.abc.Callable[..., typing.Any]: ...
|
|
@@ -25,6 +25,7 @@ from modal_proto import api_pb2
|
|
|
25
25
|
from ._environments import _get_environment_cached
|
|
26
26
|
from ._functions import _Function
|
|
27
27
|
from ._object import _get_environment_name, _Object
|
|
28
|
+
from ._output.manager import _DISABLED_OUTPUT_MANAGER
|
|
28
29
|
from ._output.pty import get_app_logs_loop, get_pty_info
|
|
29
30
|
from ._resolver import Resolver
|
|
30
31
|
from ._traceback import print_server_warnings, traceback_contains_remote_call
|
|
@@ -139,6 +140,7 @@ async def _create_all_objects(
|
|
|
139
140
|
running_app: RunningApp,
|
|
140
141
|
local_app_state: "modal.app._LocalAppState",
|
|
141
142
|
load_context: LoadContext,
|
|
143
|
+
output_mgr: OutputManager,
|
|
142
144
|
) -> None:
|
|
143
145
|
"""Create objects that have been defined but not created on the server.
|
|
144
146
|
|
|
@@ -149,7 +151,6 @@ async def _create_all_objects(
|
|
|
149
151
|
tc = load_context.task_context
|
|
150
152
|
|
|
151
153
|
resolver = Resolver()
|
|
152
|
-
output_mgr = OutputManager.get()
|
|
153
154
|
with output_mgr.display_object_tree():
|
|
154
155
|
# Get current objects, and reset all objects.
|
|
155
156
|
# Only reuse an existing object id when its type matches the object now being
|
|
@@ -377,6 +378,7 @@ async def _run_app(
|
|
|
377
378
|
environment_name: str | None = None,
|
|
378
379
|
interactive: bool = False,
|
|
379
380
|
deployment_strategy: str = "rolling",
|
|
381
|
+
stream_output: bool = True,
|
|
380
382
|
) -> AsyncGenerator["modal.app._App", None]:
|
|
381
383
|
"""mdmd:hidden"""
|
|
382
384
|
if modal._runtime.execution_context._in_import_context():
|
|
@@ -409,7 +411,8 @@ async def _run_app(
|
|
|
409
411
|
app._description = __main__.__name__
|
|
410
412
|
|
|
411
413
|
app_state = api_pb2.APP_STATE_DETACHED if detach else api_pb2.APP_STATE_EPHEMERAL
|
|
412
|
-
|
|
414
|
+
# stream_output covers the App's own status, spinner, and log stream; objects print their own output
|
|
415
|
+
output_mgr = OutputManager.get() if stream_output else _DISABLED_OUTPUT_MANAGER
|
|
413
416
|
|
|
414
417
|
if interactive and not output_mgr.is_enabled:
|
|
415
418
|
msg = "Interactive mode requires output to be enabled. (Use the the `modal.enable_output()` context manager.)"
|
|
@@ -454,7 +457,7 @@ async def _run_app(
|
|
|
454
457
|
|
|
455
458
|
try:
|
|
456
459
|
# Create all members
|
|
457
|
-
await _create_all_objects(running_app, local_app_state, load_context)
|
|
460
|
+
await _create_all_objects(running_app, local_app_state, load_context, output_mgr)
|
|
458
461
|
|
|
459
462
|
# Publish the app
|
|
460
463
|
await _publish_app(
|
|
@@ -467,7 +470,7 @@ async def _run_app(
|
|
|
467
470
|
)
|
|
468
471
|
except asyncio.CancelledError as e:
|
|
469
472
|
# this typically happens on sigint/ctrl-C during setup (the KeyboardInterrupt happens in the main thread)
|
|
470
|
-
|
|
473
|
+
output_mgr.print("Aborting app initialization...\n")
|
|
471
474
|
await _status_based_disconnect(load_context.client, running_app.app_id, e)
|
|
472
475
|
raise
|
|
473
476
|
except BaseException as e:
|
|
@@ -541,7 +544,7 @@ async def _run_app(
|
|
|
541
544
|
|
|
542
545
|
# Print completion message if output is still enabled (it may have been disabled during PTY mode)
|
|
543
546
|
# Re-fetch the output manager in case it was disabled
|
|
544
|
-
output_mgr = OutputManager.get()
|
|
547
|
+
output_mgr = OutputManager.get() if stream_output else _DISABLED_OUTPUT_MANAGER
|
|
545
548
|
if output_mgr.is_enabled:
|
|
546
549
|
output_mgr.step_completed(
|
|
547
550
|
f"App completed. [grey70]View run at [underline]{running_app.app_page_url}[/underline][/grey70]"
|
|
@@ -564,7 +567,7 @@ async def _serve_update(
|
|
|
564
567
|
# Create objects with a TaskContext for proper exception handling
|
|
565
568
|
async with TaskContext() as tc:
|
|
566
569
|
await load_context.in_place_upgrade(task_context=tc, app_id=running_app.app_id)
|
|
567
|
-
await _create_all_objects(running_app, local_app_state, load_context)
|
|
570
|
+
await _create_all_objects(running_app, local_app_state, load_context, OutputManager.get())
|
|
568
571
|
|
|
569
572
|
# Publish the updated app
|
|
570
573
|
await _publish_app(
|
|
@@ -665,7 +668,7 @@ async def _deploy_app(
|
|
|
665
668
|
|
|
666
669
|
try:
|
|
667
670
|
# Create all members
|
|
668
|
-
await _create_all_objects(running_app, local_app_state, root_load_context)
|
|
671
|
+
await _create_all_objects(running_app, local_app_state, root_load_context, OutputManager.get())
|
|
669
672
|
|
|
670
673
|
commit_info = None
|
|
671
674
|
try:
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import modal._load_context
|
|
2
|
+
import modal._output.manager
|
|
2
3
|
import modal.app
|
|
3
4
|
import modal.client
|
|
4
5
|
import modal.running_app
|
|
@@ -31,6 +32,7 @@ async def _create_all_objects(
|
|
|
31
32
|
running_app: modal.running_app.RunningApp,
|
|
32
33
|
local_app_state: modal.app._LocalAppState,
|
|
33
34
|
load_context: modal._load_context.LoadContext,
|
|
35
|
+
output_mgr: modal._output.manager.OutputManager,
|
|
34
36
|
) -> None:
|
|
35
37
|
"""Create objects that have been defined but not created on the server.
|
|
36
38
|
|
|
@@ -82,6 +84,7 @@ def _run_app(
|
|
|
82
84
|
environment_name: typing.Optional[str] = None,
|
|
83
85
|
interactive: bool = False,
|
|
84
86
|
deployment_strategy: str = "rolling",
|
|
87
|
+
stream_output: bool = True,
|
|
85
88
|
) -> typing.AsyncContextManager[modal.app._App]:
|
|
86
89
|
"""mdmd:hidden"""
|
|
87
90
|
...
|
|
@@ -185,6 +188,7 @@ class __run_app_spec(typing_extensions.Protocol):
|
|
|
185
188
|
environment_name: typing.Optional[str] = None,
|
|
186
189
|
interactive: bool = False,
|
|
187
190
|
deployment_strategy: str = "rolling",
|
|
191
|
+
stream_output: bool = True,
|
|
188
192
|
) -> synchronicity.combined_types.AsyncAndBlockingContextManager[modal.app.App]:
|
|
189
193
|
"""mdmd:hidden"""
|
|
190
194
|
...
|
|
@@ -200,6 +204,7 @@ class __run_app_spec(typing_extensions.Protocol):
|
|
|
200
204
|
environment_name: typing.Optional[str] = None,
|
|
201
205
|
interactive: bool = False,
|
|
202
206
|
deployment_strategy: str = "rolling",
|
|
207
|
+
stream_output: bool = True,
|
|
203
208
|
) -> typing.AsyncContextManager[modal.app.App]:
|
|
204
209
|
"""mdmd:hidden"""
|
|
205
210
|
...
|