modal 1.5.4.dev0__tar.gz → 1.5.4.dev2__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.4.dev0 → modal-1.5.4.dev2}/PKG-INFO +1 -1
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_environments.py +6 -2
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_functions.py +29 -7
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_image.py +50 -41
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_server.py +7 -2
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/environment.py +4 -3
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/image.py +13 -25
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/client.pyi +2 -2
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cls.py +7 -1
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cls.pyi +16 -3
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/environments.pyi +14 -2
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/functions.pyi +41 -11
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/image.pyi +6 -4
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/server.pyi +11 -2
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/types.py +38 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal.egg-info/PKG-INFO +1 -1
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal_proto/api_pb2.py +702 -702
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal_proto/api_pb2.pyi +16 -3
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal_version/__init__.py +1 -1
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/LICENSE +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/README.md +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/__init__.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/__main__.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_billing.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_clustered_functions.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_clustered_functions.pyi +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_container_entrypoint.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_function_variants.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_grpc_client.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_ipython.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_load_context.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_location.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_logs.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_logs_manager.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_logs_manager.pyi +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_object.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_output/__init__.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_output/manager.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_output/pty.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_output/rich.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_output/status.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_partial_function.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_resolver.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_resources.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_runtime/__init__.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_runtime/asgi.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_runtime/container_io_manager.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_runtime/container_io_manager.pyi +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_runtime/execution_context.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_runtime/execution_context.pyi +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_runtime/gpu_memory_snapshot.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_runtime/task_lifecycle_manager.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_runtime/task_lifecycle_manager.pyi +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_runtime/telemetry.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_runtime/user_code_event_loop.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_runtime/user_code_imports.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_serialization.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_supports_logs.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_traceback.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_tunnel.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_tunnel.pyi +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_type_manager.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/__init__.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/app_utils.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/async_utils.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/auth_token_manager.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/blob_utils.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/browser_utils.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/bytes_io_segment_payload.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/curl_utils.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/deprecation.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/display_utils.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/docker_utils.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/function_utils.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/git_utils.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/grpc_testing.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/grpc_utils.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/hash_utils.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/http_utils.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/jwt_utils.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/logger.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/mount_utils.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/name_utils.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/package_utils.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/pattern_utils.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/proxy_support.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/rand_pb_testing.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/sandbox_fs_utils.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/shell_utils.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/task_command_router_client.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/time_utils.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_vendor/__init__.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_vendor/a2wsgi_wsgi.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_vendor/cloudpickle.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_vendor/tblib.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_vendor/version.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_watcher.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_workspace.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/app.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/app.pyi +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/billing.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/billing.pyi +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/builder/2023.12.312.txt +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/builder/2023.12.txt +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/builder/2024.04.txt +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/builder/2024.10.txt +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/builder/2025.06.txt +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/builder/PREVIEW.txt +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/builder/README.md +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/builder/base-images.json +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/call_graph.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/__init__.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/_download.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/_help.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/_traceback.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/app.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/billing.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/bootstrap.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/changelog.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/cluster.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/config.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/container.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/curl.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/dashboard.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/dict.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/endpoint.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/entry_point.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/import_refs.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/launch.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/logo.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/network_file_system.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/profile.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/programs/__init__.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/programs/run_jupyter.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/programs/vscode.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/queues.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/run.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/secret.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/selector.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/shell.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/skills.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/token.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/utils.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/volume.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/workspace.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/client.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cloud_bucket_mount.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cloud_bucket_mount.pyi +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/config.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/container_process.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/container_process.pyi +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/dict.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/dict.pyi +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/environments.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/exception.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/experimental/__init__.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/experimental/flash.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/experimental/flash.pyi +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/experimental/ipython.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/file_io.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/file_io.pyi +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/file_pattern_matcher.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/functions.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/image.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/io_streams.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/io_streams.pyi +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/mount.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/mount.pyi +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/network_file_system.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/network_file_system.pyi +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/object.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/object.pyi +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/output.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/parallel_map.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/parallel_map.pyi +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/partial_function.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/partial_function.pyi +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/proxy.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/proxy.pyi +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/py.typed +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/queue.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/queue.pyi +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/retries.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/runner.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/runner.pyi +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/running_app.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/sandbox.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/sandbox.pyi +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/sandbox_fs.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/sandbox_fs.pyi +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/schedule.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/scheduler_placement.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/secret.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/secret.pyi +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/server.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/serving.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/serving.pyi +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/skills/modal/SKILL.md +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/snapshot.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/snapshot.pyi +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/stream_type.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/token_flow.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/token_flow.pyi +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/volume.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/volume.pyi +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/workspace.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/workspace.pyi +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal.egg-info/SOURCES.txt +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal.egg-info/dependency_links.txt +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal.egg-info/entry_points.txt +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal.egg-info/requires.txt +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal.egg-info/top_level.txt +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal_docs/__init__.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal_docs/gen_cli_docs.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal_docs/gen_cli_docs_main.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal_docs/gen_reference_docs.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal_docs/gen_reference_docs_main.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal_docs/mdmd/__init__.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal_docs/mdmd/mdmd.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal_docs/mdmd/signatures.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal_docs/mdmd/types.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal_docs/reference_intro.md +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal_proto/__init__.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal_proto/api_grpc.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal_proto/api_pb2_grpc.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal_proto/api_pb2_grpc.pyi +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal_proto/modal_api_grpc.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal_proto/py.typed +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal_proto/task_command_router_grpc.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal_proto/task_command_router_pb2.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal_proto/task_command_router_pb2.pyi +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal_proto/task_command_router_pb2_grpc.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal_proto/task_command_router_pb2_grpc.pyi +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal_version/__main__.py +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/pyproject.toml +0 -0
- {modal-1.5.4.dev0 → modal-1.5.4.dev2}/setup.cfg +0 -0
|
@@ -4,7 +4,7 @@ import builtins
|
|
|
4
4
|
from collections.abc import Iterable, Mapping
|
|
5
5
|
from dataclasses import dataclass
|
|
6
6
|
from datetime import datetime, timezone
|
|
7
|
-
from typing import Literal
|
|
7
|
+
from typing import Any, Literal
|
|
8
8
|
|
|
9
9
|
from google.protobuf.empty_pb2 import Empty
|
|
10
10
|
from google.protobuf.message import Message
|
|
@@ -39,6 +39,7 @@ class _EnvironmentManager:
|
|
|
39
39
|
name: str, # Name to use for the new Environment
|
|
40
40
|
*,
|
|
41
41
|
restricted: bool = False, # If True, enable RBAC restrictions on the Environment
|
|
42
|
+
experimental_options: dict[str, Any] | None = None, # Experimental options for Environment creation
|
|
42
43
|
client: _Client | None = None, # Optional client with Modal credentials
|
|
43
44
|
) -> None:
|
|
44
45
|
"""Create a new Environment.
|
|
@@ -51,7 +52,10 @@ class _EnvironmentManager:
|
|
|
51
52
|
"""
|
|
52
53
|
check_environment_name(name)
|
|
53
54
|
client = await _Client.from_env() if client is None else client
|
|
54
|
-
|
|
55
|
+
request = api_pb2.EnvironmentCreateRequest(name=name, is_managed=restricted)
|
|
56
|
+
if (experimental_options or {}).get("is_public", False):
|
|
57
|
+
request.environment_type = api_pb2.ENVIRONMENT_TYPE_PUBLIC
|
|
58
|
+
await client.stub.EnvironmentCreate(request)
|
|
55
59
|
|
|
56
60
|
async def list(
|
|
57
61
|
self,
|
|
@@ -93,7 +93,7 @@ from .proxy import _Proxy
|
|
|
93
93
|
from .retries import Retries, RetryManager
|
|
94
94
|
from .schedule import Schedule
|
|
95
95
|
from .secret import _Secret
|
|
96
|
-
from .types import FunctionStats
|
|
96
|
+
from .types import FunctionAutoscalerSettings, FunctionStats, ServerAutoscalerSettings
|
|
97
97
|
from .volume import _Volume, _volume_to_mount_proto
|
|
98
98
|
|
|
99
99
|
if TYPE_CHECKING:
|
|
@@ -1172,6 +1172,25 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
|
|
|
1172
1172
|
return obj
|
|
1173
1173
|
|
|
1174
1174
|
async def _update_autoscaler(
|
|
1175
|
+
self,
|
|
1176
|
+
*,
|
|
1177
|
+
min_containers: int | None = None,
|
|
1178
|
+
max_containers: int | None = None,
|
|
1179
|
+
buffer_containers: int | None = None,
|
|
1180
|
+
scaledown_window: int | None = None,
|
|
1181
|
+
) -> FunctionAutoscalerSettings:
|
|
1182
|
+
settings = api_pb2.AutoscalerSettings(
|
|
1183
|
+
min_containers=min_containers,
|
|
1184
|
+
max_containers=max_containers,
|
|
1185
|
+
buffer_containers=buffer_containers,
|
|
1186
|
+
scaledown_window=scaledown_window,
|
|
1187
|
+
)
|
|
1188
|
+
request = api_pb2.FunctionUpdateSchedulingParamsRequest(function_id=self.object_id, settings=settings)
|
|
1189
|
+
response = await self.client.stub.FunctionUpdateSchedulingParams(request)
|
|
1190
|
+
|
|
1191
|
+
return FunctionAutoscalerSettings._from_proto(response.current_settings)
|
|
1192
|
+
|
|
1193
|
+
async def _update_autoscaler_server(
|
|
1175
1194
|
self,
|
|
1176
1195
|
*,
|
|
1177
1196
|
min_containers: int | None = None,
|
|
@@ -1180,7 +1199,7 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
|
|
|
1180
1199
|
scaleup_window: int | None = None,
|
|
1181
1200
|
scaledown_window: int | None = None,
|
|
1182
1201
|
target_concurrency: int | None = None,
|
|
1183
|
-
) ->
|
|
1202
|
+
) -> ServerAutoscalerSettings:
|
|
1184
1203
|
settings = api_pb2.AutoscalerSettings(
|
|
1185
1204
|
min_containers=min_containers,
|
|
1186
1205
|
max_containers=max_containers,
|
|
@@ -1190,10 +1209,9 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
|
|
|
1190
1209
|
target_concurrency=target_concurrency,
|
|
1191
1210
|
)
|
|
1192
1211
|
request = api_pb2.FunctionUpdateSchedulingParamsRequest(function_id=self.object_id, settings=settings)
|
|
1193
|
-
await self.client.stub.FunctionUpdateSchedulingParams(request)
|
|
1212
|
+
response = await self.client.stub.FunctionUpdateSchedulingParams(request)
|
|
1194
1213
|
|
|
1195
|
-
|
|
1196
|
-
# and then we could return them here (would need some ad hoc dataclass, which I don't love)
|
|
1214
|
+
return ServerAutoscalerSettings._from_proto(response.current_settings)
|
|
1197
1215
|
|
|
1198
1216
|
@live_method
|
|
1199
1217
|
async def update_autoscaler(
|
|
@@ -1203,7 +1221,7 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
|
|
|
1203
1221
|
max_containers: int | None = None,
|
|
1204
1222
|
buffer_containers: int | None = None,
|
|
1205
1223
|
scaledown_window: int | None = None,
|
|
1206
|
-
) ->
|
|
1224
|
+
) -> FunctionAutoscalerSettings:
|
|
1207
1225
|
"""Override the current autoscaler behavior for this Function.
|
|
1208
1226
|
|
|
1209
1227
|
Unspecified parameters will retain their current value, i.e. either the static value
|
|
@@ -1218,6 +1236,10 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
|
|
|
1218
1236
|
buffer_containers: Extra containers to keep warm beyond current demand.
|
|
1219
1237
|
scaledown_window: Maximum duration (in seconds) idle containers wait before scaling down.
|
|
1220
1238
|
|
|
1239
|
+
Returns:
|
|
1240
|
+
A `FunctionAutoscalerSettings` dataclass which contains the current autoscaler settings
|
|
1241
|
+
of this Function after the call.
|
|
1242
|
+
|
|
1221
1243
|
Examples:
|
|
1222
1244
|
```python notest
|
|
1223
1245
|
f = modal.Function.from_name("my-app", "function")
|
|
@@ -1237,7 +1259,7 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
|
|
|
1237
1259
|
if self._is_method:
|
|
1238
1260
|
raise InvalidError("Cannot call .update_autoscaler() on a method. Call it on the class instance instead.")
|
|
1239
1261
|
|
|
1240
|
-
await self._update_autoscaler(
|
|
1262
|
+
return await self._update_autoscaler(
|
|
1241
1263
|
min_containers=min_containers,
|
|
1242
1264
|
max_containers=max_containers,
|
|
1243
1265
|
buffer_containers=buffer_containers,
|
|
@@ -117,34 +117,51 @@ def _validate_image_tag(tag: str) -> None:
|
|
|
117
117
|
check_object_name(tag, "Image tag")
|
|
118
118
|
|
|
119
119
|
|
|
120
|
-
def
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
If the name contains a '/', the part before the last '/' is extracted as
|
|
124
|
-
a namespace prefix (intended for environment/name or workspace/env/name
|
|
125
|
-
syntax). The actual image name (after the last '/') is validated as a
|
|
126
|
-
standard object name.
|
|
127
|
-
|
|
128
|
-
Returns a tuple of (prefix, "full_name:tag") where prefix is empty string
|
|
129
|
-
if no '/' is present.
|
|
130
|
-
"""
|
|
131
|
-
image_name, sep, tag = name.partition(":")
|
|
120
|
+
def _parse_image_name(partial_name: str) -> tuple[str | None, str]:
|
|
121
|
+
partial_name_no_env, sep, tag = partial_name.partition(":")
|
|
132
122
|
if not sep:
|
|
133
123
|
tag = "latest"
|
|
134
124
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
raise InvalidError("Invalid Image name: '/' prefix must be non-empty.")
|
|
125
|
+
if "/" in partial_name_no_env:
|
|
126
|
+
environment, image_name = partial_name_no_env.rsplit("/", 1)
|
|
127
|
+
if not environment:
|
|
128
|
+
raise InvalidError("Invalid Image name: environment prefix before '/' must be non-empty.")
|
|
140
129
|
if not image_name:
|
|
141
|
-
raise InvalidError("Invalid Image name: name after '/' must be non-empty.")
|
|
130
|
+
raise InvalidError("Invalid Image name: name after last '/' must be non-empty.")
|
|
131
|
+
else:
|
|
132
|
+
environment = None
|
|
133
|
+
image_name = partial_name_no_env
|
|
142
134
|
|
|
143
135
|
_validate_image_name(image_name)
|
|
144
136
|
_validate_image_tag(tag)
|
|
145
137
|
|
|
146
|
-
|
|
147
|
-
|
|
138
|
+
return environment, f"{image_name}:{tag}"
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def _upgrade_image_name(
|
|
142
|
+
partial_name: str,
|
|
143
|
+
*,
|
|
144
|
+
explicit_environment_name: str | None = None,
|
|
145
|
+
fallback_environment_name: str | None = None,
|
|
146
|
+
) -> str:
|
|
147
|
+
"""Ensures an Image name has a tag and an environment name when possible
|
|
148
|
+
|
|
149
|
+
* If no tag is present, add :latest
|
|
150
|
+
* If an explicit environment name is passed, add it as a prefix and error
|
|
151
|
+
if there is already a prefix
|
|
152
|
+
* If a fallback environment name is passed, add it only when there is no prefix
|
|
153
|
+
|
|
154
|
+
"""
|
|
155
|
+
prefix_environment, name_tag = _parse_image_name(partial_name)
|
|
156
|
+
if prefix_environment:
|
|
157
|
+
if explicit_environment_name is not None:
|
|
158
|
+
raise InvalidError("environment_name cannot be used when an Image name includes an environment prefix.")
|
|
159
|
+
return f"{prefix_environment}/{name_tag}"
|
|
160
|
+
|
|
161
|
+
environment_name = explicit_environment_name if explicit_environment_name is not None else fallback_environment_name
|
|
162
|
+
if environment_name:
|
|
163
|
+
return f"{environment_name}/{name_tag}"
|
|
164
|
+
return name_tag # no explicit environment - use just the unprefixed name:tag
|
|
148
165
|
|
|
149
166
|
|
|
150
167
|
def _validate_python_version(
|
|
@@ -2932,8 +2949,8 @@ class _Image(_Object, type_prefix="im"):
|
|
|
2932
2949
|
) -> "_Image":
|
|
2933
2950
|
"""Reference a named Image that was previously published with `.publish()`.
|
|
2934
2951
|
|
|
2935
|
-
Names can contain an optional `:tag` part
|
|
2936
|
-
|
|
2952
|
+
Names can contain an optional `:tag` part. If no tag part is included, `":latest"` is used, matching
|
|
2953
|
+
Docker conventions.
|
|
2937
2954
|
|
|
2938
2955
|
```python notest
|
|
2939
2956
|
image = modal.Image.from_name("my-image") # references my-image:latest
|
|
@@ -2944,20 +2961,16 @@ class _Image(_Object, type_prefix="im"):
|
|
|
2944
2961
|
...
|
|
2945
2962
|
```
|
|
2946
2963
|
"""
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
if namespace_prefix and environment_name:
|
|
2950
|
-
raise InvalidError("Cannot specify 'environment_name' when the image name contains a '/'.")
|
|
2964
|
+
_upgrade_image_name(name, explicit_environment_name=environment_name) # validate
|
|
2951
2965
|
|
|
2952
2966
|
async def _load(self: _Image, resolver: Resolver, load_context: LoadContext, existing_object_id: str | None):
|
|
2953
2967
|
req = api_pb2.ImageGetByTagRequest(
|
|
2954
|
-
tag=
|
|
2955
|
-
environment_name="" if namespace_prefix else load_context.environment_name,
|
|
2968
|
+
tag=_upgrade_image_name(name, fallback_environment_name=load_context.environment_name),
|
|
2956
2969
|
)
|
|
2957
2970
|
response = await load_context.client.stub.ImageGetByTag(req)
|
|
2958
2971
|
self._hydrate(response.image_id, load_context.client, None)
|
|
2959
2972
|
|
|
2960
|
-
rep = _Image._repr(
|
|
2973
|
+
rep = _Image._repr(name, environment_name)
|
|
2961
2974
|
return _Image._from_loader(
|
|
2962
2975
|
_load,
|
|
2963
2976
|
rep,
|
|
@@ -2971,13 +2984,14 @@ class _Image(_Object, type_prefix="im"):
|
|
|
2971
2984
|
name: str,
|
|
2972
2985
|
*,
|
|
2973
2986
|
environment_name: str | None = None,
|
|
2987
|
+
experimental_options: dict[str, Any] | None = None,
|
|
2974
2988
|
client: _Client | None = None,
|
|
2975
2989
|
) -> None:
|
|
2976
2990
|
"""Publish this image under the given name
|
|
2977
2991
|
|
|
2978
2992
|
The Image must already be created (typically by calling `image.build()` or `sandbox.snapshot_filesystem()`).
|
|
2979
2993
|
|
|
2980
|
-
Image names can contain an explicit tag designation
|
|
2994
|
+
Image names can contain an explicit tag designation using `name:tag`. If no tag is included in the name,
|
|
2981
2995
|
`":latest"` is used, matching Docker conventions. To publish multiple tags, call `.publish()` once per tag.
|
|
2982
2996
|
|
|
2983
2997
|
```python notest
|
|
@@ -2987,25 +3001,20 @@ class _Image(_Object, type_prefix="im"):
|
|
|
2987
3001
|
image.publish("my-image-with-numpy:v1")
|
|
2988
3002
|
```
|
|
2989
3003
|
"""
|
|
2990
|
-
namespace_prefix, tag = _parse_named_image_ref(name)
|
|
2991
|
-
|
|
2992
|
-
if namespace_prefix:
|
|
2993
|
-
if environment_name:
|
|
2994
|
-
raise InvalidError("Cannot specify 'environment_name' when the image name contains a '/'.")
|
|
2995
|
-
resolved_env = ""
|
|
2996
|
-
else:
|
|
2997
|
-
resolved_env = environment_name or config.get("environment") or ""
|
|
2998
|
-
|
|
2999
3004
|
if self._object_id is None:
|
|
3000
3005
|
raise InvalidError("Cannot publish an image that has not been created yet. Call `.build()` first.")
|
|
3001
3006
|
|
|
3002
3007
|
_client = client or await _Client.from_env()
|
|
3008
|
+
tag = _upgrade_image_name(
|
|
3009
|
+
name,
|
|
3010
|
+
explicit_environment_name=environment_name,
|
|
3011
|
+
fallback_environment_name=config.get("environment"),
|
|
3012
|
+
)
|
|
3003
3013
|
|
|
3004
3014
|
await _client.stub.ImagePublish(
|
|
3005
3015
|
api_pb2.ImagePublishRequest(
|
|
3006
3016
|
image_id=self._object_id,
|
|
3007
|
-
|
|
3008
|
-
allow_public=False,
|
|
3017
|
+
allow_public=bool((experimental_options or {}).get("is_public", False)),
|
|
3009
3018
|
tag=tag,
|
|
3010
3019
|
)
|
|
3011
3020
|
)
|
|
@@ -15,6 +15,7 @@ from ._supports_logs import _LogQueryData
|
|
|
15
15
|
from .client import _Client
|
|
16
16
|
from .cls import is_parameter
|
|
17
17
|
from .exception import InvalidError
|
|
18
|
+
from .types import ServerAutoscalerSettings
|
|
18
19
|
|
|
19
20
|
if typing.TYPE_CHECKING:
|
|
20
21
|
import modal.app
|
|
@@ -129,7 +130,7 @@ class _Server:
|
|
|
129
130
|
buffer_containers: int | None = None,
|
|
130
131
|
scaleup_window: int | None = None,
|
|
131
132
|
scaledown_window: int | None = None,
|
|
132
|
-
) ->
|
|
133
|
+
) -> ServerAutoscalerSettings:
|
|
133
134
|
"""Override the current autoscaler behavior for this Server.
|
|
134
135
|
|
|
135
136
|
Unspecified parameters will retain their current value, i.e. either the static value
|
|
@@ -146,6 +147,10 @@ class _Server:
|
|
|
146
147
|
scaleup_window: Seconds of sustained demand required before scaling up new containers.
|
|
147
148
|
scaledown_window: Maximum duration (in seconds) idle containers wait before scaling down.
|
|
148
149
|
|
|
150
|
+
Returns:
|
|
151
|
+
A `ServerAutoscalerSettings` dataclass which contains the current autoscaler settings of
|
|
152
|
+
this Server after the call.
|
|
153
|
+
|
|
149
154
|
Examples:
|
|
150
155
|
```python notest
|
|
151
156
|
server = modal.Server.from_name("my-app", "Server")
|
|
@@ -167,7 +172,7 @@ class _Server:
|
|
|
167
172
|
```
|
|
168
173
|
|
|
169
174
|
"""
|
|
170
|
-
return await self._get_service_function().
|
|
175
|
+
return await self._get_service_function()._update_autoscaler_server(
|
|
171
176
|
min_containers=min_containers,
|
|
172
177
|
max_containers=max_containers,
|
|
173
178
|
scaleup_window=scaleup_window,
|
|
@@ -72,10 +72,11 @@ def list_(json: bool = False):
|
|
|
72
72
|
@environment_cli.command("create", help="Create a new environment in the current workspace.", no_args_is_help=True)
|
|
73
73
|
@click.argument("name")
|
|
74
74
|
@click.option("--restricted", is_flag=True, default=False, help="Enable RBAC restrictions on the new environment")
|
|
75
|
-
|
|
75
|
+
@click.option("--public", is_flag=True, default=False, hidden=True)
|
|
76
|
+
def create(name: str, restricted: bool = False, public: bool = False):
|
|
76
77
|
check_environment_name(name)
|
|
77
|
-
Environment.objects.create(name, restricted=restricted)
|
|
78
|
-
prefix = "Restricted " if restricted else ""
|
|
78
|
+
Environment.objects.create(name, restricted=restricted, experimental_options={"is_public": public})
|
|
79
|
+
prefix = "Public " if public else "Restricted " if restricted else ""
|
|
79
80
|
rich.print(f"[green]✓[/green] {prefix}Environment created: {name}")
|
|
80
81
|
|
|
81
82
|
|
|
@@ -10,12 +10,12 @@ from typing import Optional
|
|
|
10
10
|
import click
|
|
11
11
|
|
|
12
12
|
from modal._environments import ensure_env
|
|
13
|
-
from modal._image import
|
|
13
|
+
from modal._image import _upgrade_image_name
|
|
14
14
|
from modal._utils.async_utils import synchronizer
|
|
15
15
|
from modal._utils.time_utils import timestamp_to_localized_str
|
|
16
16
|
from modal.cli.utils import display_table, env_option
|
|
17
17
|
from modal.client import _Client
|
|
18
|
-
from modal.
|
|
18
|
+
from modal.config import config
|
|
19
19
|
from modal.output import OutputManager
|
|
20
20
|
from modal_proto import api_pb2
|
|
21
21
|
|
|
@@ -91,14 +91,12 @@ async def _iter_tag_pages(
|
|
|
91
91
|
|
|
92
92
|
async def _fetch_history_page(
|
|
93
93
|
client: _Client,
|
|
94
|
-
|
|
95
|
-
tag: str,
|
|
94
|
+
name_tag: str,
|
|
96
95
|
page_token: str,
|
|
97
96
|
) -> api_pb2.ImageTagRevisionsResponse:
|
|
98
97
|
return await client.stub.ImageTagRevisions(
|
|
99
98
|
api_pb2.ImageTagRevisionsRequest(
|
|
100
|
-
tag=
|
|
101
|
-
environment_name=env,
|
|
99
|
+
tag=name_tag,
|
|
102
100
|
max_objects=IMAGE_NAMES_HISTORY_PAGE_SIZE,
|
|
103
101
|
page_token=page_token,
|
|
104
102
|
)
|
|
@@ -106,7 +104,7 @@ async def _fetch_history_page(
|
|
|
106
104
|
|
|
107
105
|
|
|
108
106
|
async def _iter_history_pages(
|
|
109
|
-
client: _Client,
|
|
107
|
+
client: _Client, name_tag: str, first_page: api_pb2.ImageTagRevisionsResponse
|
|
110
108
|
) -> AsyncIterator[api_pb2.ImageTagRevisionsResponse]:
|
|
111
109
|
response = first_page
|
|
112
110
|
|
|
@@ -116,7 +114,7 @@ async def _iter_history_pages(
|
|
|
116
114
|
if not response.next_page_token:
|
|
117
115
|
return
|
|
118
116
|
await asyncio.sleep(IMAGE_NAMES_HISTORY_PAGE_DELAY_SECONDS)
|
|
119
|
-
response = await _fetch_history_page(client,
|
|
117
|
+
response = await _fetch_history_page(client, name_tag, response.next_page_token)
|
|
120
118
|
|
|
121
119
|
|
|
122
120
|
@image_names_cli.command("list", help="List named Images.")
|
|
@@ -160,36 +158,26 @@ async def list_(
|
|
|
160
158
|
"history", help="Show publishing history for a named Image.", hidden=True, no_args_is_help=True
|
|
161
159
|
)
|
|
162
160
|
@click.argument("name")
|
|
163
|
-
@env_option
|
|
164
161
|
@click.option("--json", is_flag=True, default=False)
|
|
165
162
|
@synchronizer.create_blocking
|
|
166
163
|
async def history(
|
|
167
164
|
name: str,
|
|
168
|
-
env: Optional[str] = None,
|
|
169
165
|
json: bool = False,
|
|
170
166
|
):
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
except InvalidError as exc:
|
|
176
|
-
raise click.UsageError(str(exc)) from exc
|
|
177
|
-
|
|
178
|
-
if namespace_prefix:
|
|
179
|
-
if explicit_env is not None:
|
|
180
|
-
raise click.UsageError("Cannot specify '--env' when the image name contains a '/'.")
|
|
181
|
-
env = ""
|
|
182
|
-
|
|
167
|
+
upgraded_image_name = _upgrade_image_name(
|
|
168
|
+
name,
|
|
169
|
+
fallback_environment_name=config.get("environment"),
|
|
170
|
+
)
|
|
183
171
|
client = await _Client.from_env()
|
|
184
172
|
|
|
185
|
-
first_page = await _fetch_history_page(client,
|
|
173
|
+
first_page = await _fetch_history_page(client, upgraded_image_name, "")
|
|
186
174
|
if not first_page.items:
|
|
187
175
|
raise click.ClickException(f"No publishing history found for named image {first_page.tag!r}.")
|
|
188
176
|
|
|
189
177
|
if json:
|
|
190
178
|
click.echo("[", nl=False)
|
|
191
179
|
count = 0
|
|
192
|
-
async for response in _iter_history_pages(client,
|
|
180
|
+
async for response in _iter_history_pages(client, upgraded_image_name, first_page):
|
|
193
181
|
for item in response.items:
|
|
194
182
|
if count:
|
|
195
183
|
click.echo(",", nl=False)
|
|
@@ -200,7 +188,7 @@ async def history(
|
|
|
200
188
|
|
|
201
189
|
count = 0
|
|
202
190
|
show_title = True
|
|
203
|
-
async for response in _iter_history_pages(client,
|
|
191
|
+
async for response in _iter_history_pages(client, upgraded_image_name, first_page):
|
|
204
192
|
if response.items:
|
|
205
193
|
title = f"History for {response.tag}" if show_title else ""
|
|
206
194
|
display_table(
|
|
@@ -37,7 +37,7 @@ class _Client:
|
|
|
37
37
|
server_url: str,
|
|
38
38
|
client_type: int,
|
|
39
39
|
credentials: typing.Optional[tuple[str, str]],
|
|
40
|
-
version: str = "1.5.4.
|
|
40
|
+
version: str = "1.5.4.dev2",
|
|
41
41
|
):
|
|
42
42
|
"""mdmd:hidden
|
|
43
43
|
The Modal client object is not intended to be instantiated directly by users.
|
|
@@ -207,7 +207,7 @@ class Client:
|
|
|
207
207
|
server_url: str,
|
|
208
208
|
client_type: int,
|
|
209
209
|
credentials: typing.Optional[tuple[str, str]],
|
|
210
|
-
version: str = "1.5.4.
|
|
210
|
+
version: str = "1.5.4.dev2",
|
|
211
211
|
):
|
|
212
212
|
"""mdmd:hidden
|
|
213
213
|
The Modal client object is not intended to be instantiated directly by users.
|
|
@@ -33,6 +33,7 @@ from .cloud_bucket_mount import _CloudBucketMount
|
|
|
33
33
|
from .exception import ExecutionError, InvalidError, NotFoundError
|
|
34
34
|
from .retries import Retries
|
|
35
35
|
from .secret import _Secret
|
|
36
|
+
from .types import FunctionAutoscalerSettings
|
|
36
37
|
from .volume import _Volume
|
|
37
38
|
|
|
38
39
|
T = TypeVar("T")
|
|
@@ -288,7 +289,7 @@ class _Obj:
|
|
|
288
289
|
max_containers: int | None = None,
|
|
289
290
|
scaledown_window: int | None = None,
|
|
290
291
|
buffer_containers: int | None = None,
|
|
291
|
-
) ->
|
|
292
|
+
) -> FunctionAutoscalerSettings:
|
|
292
293
|
"""Override the current autoscaler behavior for this Cls instance.
|
|
293
294
|
|
|
294
295
|
Unspecified parameters will retain their current value, i.e. either the static value
|
|
@@ -306,6 +307,10 @@ class _Obj:
|
|
|
306
307
|
scaledown_window: Idle seconds before scaling down a container; omit to leave unchanged.
|
|
307
308
|
buffer_containers: Extra idle containers under load; omit to leave unchanged.
|
|
308
309
|
|
|
310
|
+
Returns:
|
|
311
|
+
An `FunctionAutoscalerSettings` dataclass which contains the current autoscaler settings
|
|
312
|
+
of this Cls instance after the call.
|
|
313
|
+
|
|
309
314
|
Examples:
|
|
310
315
|
```python notest
|
|
311
316
|
Model = modal.Cls.from_name("my-app", "Model")
|
|
@@ -321,6 +326,7 @@ class _Obj:
|
|
|
321
326
|
"""
|
|
322
327
|
if not self._cls.is_hydrated and not self._cls._is_local():
|
|
323
328
|
await self._cls.hydrate()
|
|
329
|
+
|
|
324
330
|
return await self._cached_service_function().update_autoscaler(
|
|
325
331
|
min_containers=min_containers,
|
|
326
332
|
max_containers=max_containers,
|
|
@@ -13,6 +13,7 @@ import modal.object
|
|
|
13
13
|
import modal.partial_function
|
|
14
14
|
import modal.retries
|
|
15
15
|
import modal.secret
|
|
16
|
+
import modal.types
|
|
16
17
|
import modal.volume
|
|
17
18
|
import modal_proto.api_pb2
|
|
18
19
|
import pathlib
|
|
@@ -67,7 +68,7 @@ class _Obj:
|
|
|
67
68
|
max_containers: typing.Optional[int] = None,
|
|
68
69
|
scaledown_window: typing.Optional[int] = None,
|
|
69
70
|
buffer_containers: typing.Optional[int] = None,
|
|
70
|
-
) ->
|
|
71
|
+
) -> modal.types.FunctionAutoscalerSettings:
|
|
71
72
|
"""Override the current autoscaler behavior for this Cls instance.
|
|
72
73
|
|
|
73
74
|
Unspecified parameters will retain their current value, i.e. either the static value
|
|
@@ -85,6 +86,10 @@ class _Obj:
|
|
|
85
86
|
scaledown_window: Idle seconds before scaling down a container; omit to leave unchanged.
|
|
86
87
|
buffer_containers: Extra idle containers under load; omit to leave unchanged.
|
|
87
88
|
|
|
89
|
+
Returns:
|
|
90
|
+
An `FunctionAutoscalerSettings` dataclass which contains the current autoscaler settings
|
|
91
|
+
of this Cls instance after the call.
|
|
92
|
+
|
|
88
93
|
Examples:
|
|
89
94
|
```python notest
|
|
90
95
|
Model = modal.Cls.from_name("my-app", "Model")
|
|
@@ -150,7 +155,7 @@ class Obj:
|
|
|
150
155
|
max_containers: typing.Optional[int] = None,
|
|
151
156
|
scaledown_window: typing.Optional[int] = None,
|
|
152
157
|
buffer_containers: typing.Optional[int] = None,
|
|
153
|
-
) ->
|
|
158
|
+
) -> modal.types.FunctionAutoscalerSettings:
|
|
154
159
|
"""Override the current autoscaler behavior for this Cls instance.
|
|
155
160
|
|
|
156
161
|
Unspecified parameters will retain their current value, i.e. either the static value
|
|
@@ -168,6 +173,10 @@ class Obj:
|
|
|
168
173
|
scaledown_window: Idle seconds before scaling down a container; omit to leave unchanged.
|
|
169
174
|
buffer_containers: Extra idle containers under load; omit to leave unchanged.
|
|
170
175
|
|
|
176
|
+
Returns:
|
|
177
|
+
An `FunctionAutoscalerSettings` dataclass which contains the current autoscaler settings
|
|
178
|
+
of this Cls instance after the call.
|
|
179
|
+
|
|
171
180
|
Examples:
|
|
172
181
|
```python notest
|
|
173
182
|
Model = modal.Cls.from_name("my-app", "Model")
|
|
@@ -190,7 +199,7 @@ class Obj:
|
|
|
190
199
|
max_containers: typing.Optional[int] = None,
|
|
191
200
|
scaledown_window: typing.Optional[int] = None,
|
|
192
201
|
buffer_containers: typing.Optional[int] = None,
|
|
193
|
-
) ->
|
|
202
|
+
) -> modal.types.FunctionAutoscalerSettings:
|
|
194
203
|
"""Override the current autoscaler behavior for this Cls instance.
|
|
195
204
|
|
|
196
205
|
Unspecified parameters will retain their current value, i.e. either the static value
|
|
@@ -208,6 +217,10 @@ class Obj:
|
|
|
208
217
|
scaledown_window: Idle seconds before scaling down a container; omit to leave unchanged.
|
|
209
218
|
buffer_containers: Extra idle containers under load; omit to leave unchanged.
|
|
210
219
|
|
|
220
|
+
Returns:
|
|
221
|
+
An `FunctionAutoscalerSettings` dataclass which contains the current autoscaler settings
|
|
222
|
+
of this Cls instance after the call.
|
|
223
|
+
|
|
211
224
|
Examples:
|
|
212
225
|
```python notest
|
|
213
226
|
Model = modal.Cls.from_name("my-app", "Model")
|
|
@@ -18,7 +18,13 @@ class EnvironmentManager:
|
|
|
18
18
|
|
|
19
19
|
class __create_spec(typing_extensions.Protocol):
|
|
20
20
|
def __call__(
|
|
21
|
-
self,
|
|
21
|
+
self,
|
|
22
|
+
/,
|
|
23
|
+
name: str,
|
|
24
|
+
*,
|
|
25
|
+
restricted: bool = False,
|
|
26
|
+
experimental_options: typing.Optional[dict[str, typing.Any]] = None,
|
|
27
|
+
client: typing.Optional[modal.client.Client] = None,
|
|
22
28
|
) -> None:
|
|
23
29
|
"""Create a new Environment.
|
|
24
30
|
|
|
@@ -31,7 +37,13 @@ class EnvironmentManager:
|
|
|
31
37
|
...
|
|
32
38
|
|
|
33
39
|
async def aio(
|
|
34
|
-
self,
|
|
40
|
+
self,
|
|
41
|
+
/,
|
|
42
|
+
name: str,
|
|
43
|
+
*,
|
|
44
|
+
restricted: bool = False,
|
|
45
|
+
experimental_options: typing.Optional[dict[str, typing.Any]] = None,
|
|
46
|
+
client: typing.Optional[modal.client.Client] = None,
|
|
35
47
|
) -> None:
|
|
36
48
|
"""Create a new Environment.
|
|
37
49
|
|