modal 1.6.3.dev12__tar.gz → 1.6.4.dev0__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.3.dev12 → modal-1.6.4.dev0}/PKG-INFO +1 -1
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_image.py +47 -13
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_utils/docker_utils.py +10 -1
- modal-1.6.4.dev0/modal/builder/PREVIEW.txt +17 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/builder/base-images.json +3 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/cli/endpoint.py +49 -7
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/cli/profile.py +1 -1
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/cli/workspace.py +1 -1
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/client.pyi +2 -2
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/image.pyi +34 -14
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/io_streams.py +26 -14
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/io_streams.pyi +2 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/mount.py +9 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal.egg-info/PKG-INFO +1 -1
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal.egg-info/SOURCES.txt +1 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal_proto/api_grpc.py +16 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal_proto/api_pb2.py +1205 -1175
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal_proto/api_pb2.pyi +52 -1
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal_proto/api_pb2_grpc.py +33 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal_proto/api_pb2_grpc.pyi +10 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal_proto/modal_api_grpc.py +1 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal_version/__init__.py +1 -1
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/LICENSE +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/README.md +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/__init__.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/__main__.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_billing.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_cluster.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_cluster.pyi +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_container_entrypoint.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_environments.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_function_variants.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_functions.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_grpc_client.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_ipython.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_load_context.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_location.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_logs.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_logs_manager.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_logs_manager.pyi +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_metrics.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_metrics.pyi +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_object.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_outbound_policy.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_outbound_policy.pyi +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_output/__init__.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_output/manager.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_output/pty.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_output/rich.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_output/status.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_partial_function.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_resolver.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_resources.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_runtime/__init__.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_runtime/asgi.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_runtime/container_io_manager.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_runtime/container_io_manager.pyi +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_runtime/execution_context.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_runtime/execution_context.pyi +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_runtime/gpu_memory_snapshot.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_runtime/task_lifecycle_manager.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_runtime/task_lifecycle_manager.pyi +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_runtime/telemetry.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_runtime/user_code_event_loop.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_runtime/user_code_imports.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_serialization.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_server.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_server.pyi +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_supports_logs.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_traceback.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_tunnel.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_tunnel.pyi +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_type_manager.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_utils/__init__.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_utils/app_utils.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_utils/async_utils.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_utils/auth_token_manager.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_utils/blob_utils.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_utils/browser_utils.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_utils/bytes_io_segment_payload.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_utils/curl_utils.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_utils/deprecation.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_utils/display_utils.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_utils/function_utils.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_utils/git_utils.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_utils/grpc_testing.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_utils/grpc_utils.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_utils/hash_utils.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_utils/http_utils.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_utils/idle_countdown.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_utils/jwt_utils.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_utils/logger.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_utils/mount_utils.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_utils/name_utils.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_utils/oauth.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_utils/package_utils.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_utils/pattern_utils.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_utils/proxy_support.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_utils/rand_pb_testing.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_utils/sandbox_fs_utils.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_utils/shell_utils.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_utils/time_utils.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_vendor/__init__.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_vendor/a2wsgi_wsgi.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_vendor/cloudpickle.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_vendor/tblib.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_vendor/version.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_watcher.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/_workspace.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/app.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/app.pyi +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/billing.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/billing.pyi +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/builder/2023.12.312.txt +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/builder/2023.12.txt +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/builder/2024.04.txt +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/builder/2024.10.txt +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/builder/2025.06.txt +0 -0
- /modal-1.6.3.dev12/modal/builder/PREVIEW.txt → /modal-1.6.4.dev0/modal/builder/2026.10.txt +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/builder/README.md +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/call_graph.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/cli/__init__.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/cli/_download.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/cli/_help.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/cli/_logs.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/cli/_stats.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/cli/_traceback.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/cli/app.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/cli/billing.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/cli/changelog.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/cli/config.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/cli/container.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/cli/curl.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/cli/dashboard.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/cli/dict.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/cli/entry_point.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/cli/environment.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/cli/function.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/cli/image.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/cli/import_refs.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/cli/logo.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/cli/network_file_system.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/cli/queues.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/cli/run.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/cli/secret.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/cli/selector.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/cli/server.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/cli/shell.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/cli/skills.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/cli/token.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/cli/utils.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/cli/volume.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/client.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/cloud_bucket_mount.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/cloud_bucket_mount.pyi +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/cls.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/cls.pyi +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/cluster.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/cluster.pyi +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/config.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/container_process.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/container_process.pyi +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/dict.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/dict.pyi +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/environments.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/environments.pyi +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/exception.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/experimental/__init__.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/experimental/_flash_container_entry.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/experimental/flash.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/experimental/flash.pyi +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/experimental/flash_server.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/experimental/flash_server.pyi +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/experimental/ipython.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/file_pattern_matcher.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/functions.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/functions.pyi +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/image.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/mount.pyi +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/network_file_system.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/network_file_system.pyi +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/object.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/object.pyi +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/output.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/parallel_map.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/parallel_map.pyi +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/partial_function.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/partial_function.pyi +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/proxy.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/proxy.pyi +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/py.typed +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/queue.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/queue.pyi +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/retries.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/runner.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/runner.pyi +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/running_app.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/sandbox/__init__.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/sandbox/_common.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/sandbox/_filesystem.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/sandbox/_impl_persistent.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/sandbox/_impl_v1.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/sandbox/_impl_v2.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/sandbox/_sandbox.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/sandbox/_sidecar.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/sandbox/_snapshot.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/sandbox/_task_command_router_client.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/sandbox/sandbox.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/sandbox/sandbox.pyi +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/schedule.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/scheduler_placement.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/secret.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/secret.pyi +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/server.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/server.pyi +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/serving.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/serving.pyi +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/skills/modal/SKILL.md +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/stream_type.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/token_flow.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/token_flow.pyi +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/types.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/volume.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/volume.pyi +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/workspace.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal/workspace.pyi +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal.egg-info/dependency_links.txt +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal.egg-info/entry_points.txt +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal.egg-info/requires.txt +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal.egg-info/top_level.txt +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal_docs/__init__.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal_docs/gen_cli_docs.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal_docs/gen_cli_docs_main.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal_docs/gen_reference_docs.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal_docs/gen_reference_docs_main.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal_docs/mdmd/__init__.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal_docs/mdmd/mdmd.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal_docs/mdmd/signatures.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal_docs/mdmd/types.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal_docs/reference_intro.md +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal_proto/__init__.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal_proto/py.typed +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal_proto/task_command_router_grpc.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal_proto/task_command_router_pb2.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal_proto/task_command_router_pb2.pyi +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal_proto/task_command_router_pb2_grpc.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal_proto/task_command_router_pb2_grpc.pyi +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/modal_version/__main__.py +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/pyproject.toml +0 -0
- {modal-1.6.3.dev12 → modal-1.6.4.dev0}/setup.cfg +0 -0
|
@@ -40,6 +40,7 @@ from ._utils.blob_utils import MAX_OBJECT_SIZE_BYTES
|
|
|
40
40
|
from ._utils.docker_utils import (
|
|
41
41
|
extract_copy_command_patterns,
|
|
42
42
|
find_dockerignore_file,
|
|
43
|
+
is_multi_stage_dockerfile,
|
|
43
44
|
splittable_from_line_index,
|
|
44
45
|
)
|
|
45
46
|
from ._utils.function_utils import FunctionSourceInfo, parse_gpu_config
|
|
@@ -70,8 +71,8 @@ if typing.TYPE_CHECKING:
|
|
|
70
71
|
import modal.client
|
|
71
72
|
|
|
72
73
|
# This is used for both type checking and runtime validation
|
|
73
|
-
ImageBuilderVersion = Literal["2023.12", "2024.04", "2024.10", "2025.06", "PREVIEW"]
|
|
74
|
-
LATEST_IMAGE_BUILDER_VERSION: ImageBuilderVersion = "
|
|
74
|
+
ImageBuilderVersion = Literal["2023.12", "2024.04", "2024.10", "2025.06", "2026.10", "PREVIEW"]
|
|
75
|
+
LATEST_IMAGE_BUILDER_VERSION: ImageBuilderVersion = "2026.10"
|
|
75
76
|
|
|
76
77
|
# Note: we also define supported Python versions via logic at the top of the package __init__.py
|
|
77
78
|
# so that we fail fast / clearly in unsupported containers. Additionally, we enumerate the supported
|
|
@@ -79,6 +80,7 @@ LATEST_IMAGE_BUILDER_VERSION: ImageBuilderVersion = "2025.06"
|
|
|
79
80
|
# Consider consolidating these multiple sources of truth?
|
|
80
81
|
SUPPORTED_PYTHON_SERIES: dict[ImageBuilderVersion, list[str]] = {
|
|
81
82
|
"PREVIEW": ["3.11", "3.12", "3.13", "3.14", "3.14t", "3.15", "3.15t"],
|
|
83
|
+
"2026.10": ["3.11", "3.12", "3.13", "3.14", "3.14t", "3.15", "3.15t"],
|
|
82
84
|
"2025.06": ["3.10", "3.11", "3.12", "3.13", "3.14", "3.14t", "3.15", "3.15t"],
|
|
83
85
|
"2024.10": ["3.10", "3.11", "3.12", "3.13"],
|
|
84
86
|
"2024.04": ["3.10", "3.11", "3.12"],
|
|
@@ -2405,7 +2407,11 @@ class _Image(_Object, type_prefix="im"):
|
|
|
2405
2407
|
add_python: str | None = None,
|
|
2406
2408
|
**kwargs,
|
|
2407
2409
|
) -> "_Image":
|
|
2408
|
-
"""
|
|
2410
|
+
"""mdmd:hidden
|
|
2411
|
+
Build a Modal image from a private image in Google Cloud Platform (GCP) Artifact Registry.
|
|
2412
|
+
|
|
2413
|
+
**Note:** This constructor is superseded by `Image.from_registry()`, which can also authenticate
|
|
2414
|
+
to private repositories when provided with the appropriate keys in a `modal.Secret`.
|
|
2409
2415
|
|
|
2410
2416
|
You will need to pass a `modal.Secret` containing [your GCP service account key data](https://cloud.google.com/iam/docs/keys-create-delete#creating)
|
|
2411
2417
|
as `SERVICE_ACCOUNT_JSON`. This can be done from the [Secrets](https://modal.com/secrets) page.
|
|
@@ -2466,11 +2472,15 @@ class _Image(_Object, type_prefix="im"):
|
|
|
2466
2472
|
add_python: str | None = None,
|
|
2467
2473
|
**kwargs,
|
|
2468
2474
|
) -> "_Image":
|
|
2469
|
-
"""
|
|
2475
|
+
"""mdmd:hidden
|
|
2476
|
+
Build a Modal image from a private image in AWS Elastic Container Registry (ECR).
|
|
2470
2477
|
|
|
2471
2478
|
You will need to pass a `modal.Secret` containing either IAM user credentials or OIDC
|
|
2472
2479
|
configuration to access the target ECR registry.
|
|
2473
2480
|
|
|
2481
|
+
**Note:** This constructor is superseded by `Image.from_registry()`, which can also authenticate
|
|
2482
|
+
to private repositories when provided with the appropriate keys in a `modal.Secret`.
|
|
2483
|
+
|
|
2474
2484
|
For IAM user authentication, set `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and `AWS_REGION`.
|
|
2475
2485
|
|
|
2476
2486
|
For OIDC authentication, set `AWS_ROLE_ARN` and `AWS_REGION`.
|
|
@@ -2523,28 +2533,33 @@ class _Image(_Object, type_prefix="im"):
|
|
|
2523
2533
|
*,
|
|
2524
2534
|
force_build: bool = False,
|
|
2525
2535
|
context_dir: Path | str | None = None,
|
|
2526
|
-
|
|
2536
|
+
ignore: Sequence[str] | Callable[[Path], bool] = AUTO_DOCKERIGNORE,
|
|
2537
|
+
build_args: dict[str, str] = {},
|
|
2538
|
+
registry_secret: _Secret | None = None,
|
|
2527
2539
|
secrets: Collection[_Secret] | None = None,
|
|
2540
|
+
env: dict[str, str | None] | None = None,
|
|
2528
2541
|
gpu: str | None = None,
|
|
2529
2542
|
add_python: str | None = None,
|
|
2530
|
-
build_args: dict[str, str] = {},
|
|
2531
|
-
ignore: Sequence[str] | Callable[[Path], bool] = AUTO_DOCKERIGNORE,
|
|
2532
2543
|
) -> "_Image":
|
|
2533
2544
|
"""Build a Modal image from a local Dockerfile.
|
|
2534
2545
|
|
|
2535
2546
|
If your Dockerfile does not have Python installed, you can use the `add_python` parameter
|
|
2536
2547
|
to specify a version of Python to add to the image.
|
|
2537
2548
|
|
|
2549
|
+
A `registry_secret` can be provided to pull the base image from a private registry.
|
|
2550
|
+
Currently this is supported only for single-stage Dockerfiles.
|
|
2551
|
+
|
|
2538
2552
|
Args:
|
|
2539
2553
|
path: Path to the Dockerfile on the local machine.
|
|
2540
2554
|
force_build: If True, skip cached image builds.
|
|
2541
2555
|
context_dir: Build context directory for resolving relative COPY paths.
|
|
2556
|
+
ignore: Ignore rules for the implicit context mount (defaults to auto ``.dockerignore`` behavior).
|
|
2557
|
+
build_args: Dockerfile ``ARG`` values forwarded to the build.
|
|
2558
|
+
registry_secret: Optional Secret with credentials for pulling the base image from a private registry.
|
|
2559
|
+
secrets: Secrets injected as environment variables in the build container.
|
|
2542
2560
|
env: Environment variables set in the build container.
|
|
2543
|
-
|
|
2544
|
-
gpu: GPU type to attach to the builder container.
|
|
2561
|
+
gpu: GPU type to attach to the build container.
|
|
2545
2562
|
add_python: Standalone Python version to add when the Dockerfile does not install Python.
|
|
2546
|
-
build_args: Dockerfile ``ARG`` values forwarded to the build.
|
|
2547
|
-
ignore: Ignore rules for the implicit context mount (defaults to auto ``.dockerignore`` behavior).
|
|
2548
2563
|
|
|
2549
2564
|
Returns:
|
|
2550
2565
|
An `Image` built from the Dockerfile plus Modal runtime dependencies.
|
|
@@ -2590,6 +2605,12 @@ class _Image(_Object, type_prefix="im"):
|
|
|
2590
2605
|
add_python="3.12",
|
|
2591
2606
|
ignore=FilePatternMatcher.from_file("/path/to/dockerignore"),
|
|
2592
2607
|
)
|
|
2608
|
+
|
|
2609
|
+
# Pull the Dockerfile's base image from a private registry.
|
|
2610
|
+
image = modal.Image.from_dockerfile(
|
|
2611
|
+
"./Dockerfile",
|
|
2612
|
+
registry_secret=modal.Secret.from_name("my-registry-secret"),
|
|
2613
|
+
)
|
|
2593
2614
|
```
|
|
2594
2615
|
"""
|
|
2595
2616
|
|
|
@@ -2602,7 +2623,15 @@ class _Image(_Object, type_prefix="im"):
|
|
|
2602
2623
|
ignore=ignore, dockerfile_path=Path(path), context_dir=context_dir
|
|
2603
2624
|
)
|
|
2604
2625
|
|
|
2605
|
-
|
|
2626
|
+
registry_config = (
|
|
2627
|
+
_ImageRegistryConfig(secret=registry_secret, infer_auth_type=True) if registry_secret is not None else None
|
|
2628
|
+
)
|
|
2629
|
+
|
|
2630
|
+
def dockerfile_image(
|
|
2631
|
+
commands: list[str],
|
|
2632
|
+
base_images: dict[str, _Image] | None = None,
|
|
2633
|
+
image_registry_config: _ImageRegistryConfig | None = None,
|
|
2634
|
+
) -> _Image:
|
|
2606
2635
|
return _Image._from_args(
|
|
2607
2636
|
base_images=base_images,
|
|
2608
2637
|
dockerfile_function=lambda version: DockerfileSpec(commands=commands, context_files={}),
|
|
@@ -2610,6 +2639,7 @@ class _Image(_Object, type_prefix="im"):
|
|
|
2610
2639
|
gpu_config=gpu_config,
|
|
2611
2640
|
secrets=secrets,
|
|
2612
2641
|
build_args=build_args,
|
|
2642
|
+
image_registry_config=image_registry_config,
|
|
2613
2643
|
force_build=force_build,
|
|
2614
2644
|
)
|
|
2615
2645
|
|
|
@@ -2648,19 +2678,23 @@ class _Image(_Object, type_prefix="im"):
|
|
|
2648
2678
|
)
|
|
2649
2679
|
with open(os.path.expanduser(path)) as f:
|
|
2650
2680
|
dockerfile_lines = f.read().split("\n")
|
|
2681
|
+
if registry_secret is not None and is_multi_stage_dockerfile(dockerfile_lines):
|
|
2682
|
+
raise InvalidError("`registry_secret` is not supported with multi-stage Dockerfiles.")
|
|
2651
2683
|
|
|
2652
2684
|
# Builder versions after 2025.06 put the FROM line of a single-stage Dockerfile in its own image.
|
|
2653
2685
|
# Dockerfiles the split could change (see splittable_from_line_index) stay in one layer.
|
|
2654
2686
|
from_index = splittable_from_line_index(dockerfile_lines) if builder_version > "2025.06" else None
|
|
2655
2687
|
if from_index is None:
|
|
2656
|
-
image = dockerfile_image(dockerfile_lines)
|
|
2688
|
+
image = dockerfile_image(dockerfile_lines, image_registry_config=registry_config)
|
|
2657
2689
|
else:
|
|
2658
2690
|
# Drop the lines above FROM so Dockerfiles that differ only in header comments or blank lines
|
|
2659
2691
|
# share the cached image. Those lines can only be comments or blank lines, since
|
|
2660
2692
|
# splittable_from_line_index rejects parser directives.
|
|
2661
2693
|
from_lines = [dockerfile_lines[from_index]]
|
|
2694
|
+
# Only this layer pulls from the registry; the layers above it build on top of it.
|
|
2662
2695
|
from_image = _Image._from_args(
|
|
2663
2696
|
dockerfile_function=lambda version: DockerfileSpec(commands=from_lines, context_files={}),
|
|
2697
|
+
image_registry_config=registry_config,
|
|
2664
2698
|
force_build=force_build,
|
|
2665
2699
|
)
|
|
2666
2700
|
rest = dockerfile_lines[from_index + 1 :]
|
|
@@ -79,6 +79,15 @@ _FROM_ALIAS_PATTERN = re.compile(r"\sAS\s+\S+\s*$", re.IGNORECASE)
|
|
|
79
79
|
_PARSER_DIRECTIVE_PATTERN = re.compile(r"^#\s*[a-zA-Z][a-zA-Z0-9]*\s*=")
|
|
80
80
|
|
|
81
81
|
|
|
82
|
+
def is_multi_stage_dockerfile(dockerfile_lines: Sequence[str]) -> bool:
|
|
83
|
+
"""Return whether more than one line starts with a FROM instruction.
|
|
84
|
+
|
|
85
|
+
Can have false-positives for Dockerfiles with a Heredoc bodies of continuation lines
|
|
86
|
+
that contain "from" tokens.
|
|
87
|
+
"""
|
|
88
|
+
return sum(1 for line in dockerfile_lines if _FROM_PATTERN.match(line)) > 1
|
|
89
|
+
|
|
90
|
+
|
|
82
91
|
def splittable_from_line_index(dockerfile_lines: Sequence[str]) -> int | None:
|
|
83
92
|
"""Return the line index of the FROM instruction if it can be built as its own image.
|
|
84
93
|
|
|
@@ -96,7 +105,7 @@ def splittable_from_line_index(dockerfile_lines: Sequence[str]) -> int | None:
|
|
|
96
105
|
return None
|
|
97
106
|
if any(_PARSER_DIRECTIVE_PATTERN.match(line.strip()) for line in dockerfile_lines[:start]):
|
|
98
107
|
return None
|
|
99
|
-
if
|
|
108
|
+
if is_multi_stage_dockerfile(dockerfile_lines):
|
|
100
109
|
return None
|
|
101
110
|
return start
|
|
102
111
|
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
aiohappyeyeballs==2.7.1
|
|
2
|
+
aiohttp==3.14.5
|
|
3
|
+
aiosignal==1.4.0
|
|
4
|
+
attrs==26.1.0
|
|
5
|
+
cbor2==5.9.0
|
|
6
|
+
certifi==2026.10.19
|
|
7
|
+
frozenlist==1.8.0
|
|
8
|
+
grpclib==0.4.9
|
|
9
|
+
h2==4.4.1
|
|
10
|
+
hpack==4.2.0
|
|
11
|
+
hyperframe==6.1.0
|
|
12
|
+
idna==3.20
|
|
13
|
+
multidict==7.1.0
|
|
14
|
+
propcache==0.5.4
|
|
15
|
+
protobuf==7.36.2
|
|
16
|
+
typing_extensions==4.16.0
|
|
17
|
+
yarl==1.25.1
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"debian": {
|
|
3
3
|
"PREVIEW": "trixie",
|
|
4
|
+
"2026.10": "trixie",
|
|
4
5
|
"2025.06": "bookworm",
|
|
5
6
|
"2024.10": "bookworm",
|
|
6
7
|
"2024.04": "bookworm",
|
|
@@ -38,6 +39,7 @@
|
|
|
38
39
|
},
|
|
39
40
|
"micromamba": {
|
|
40
41
|
"PREVIEW": "2.9.0-debian13-slim",
|
|
42
|
+
"2026.10": "2.9.0-debian13-slim",
|
|
41
43
|
"2025.06": "2.1.1-debian12-slim",
|
|
42
44
|
"2024.10": "1.5.10-bookworm-slim",
|
|
43
45
|
"2024.04": "1.5.8-bookworm-slim",
|
|
@@ -45,6 +47,7 @@
|
|
|
45
47
|
},
|
|
46
48
|
"package_tools": {
|
|
47
49
|
"PREVIEW": "pip wheel uv",
|
|
50
|
+
"2026.10": "pip wheel uv",
|
|
48
51
|
"2025.06": "pip wheel uv",
|
|
49
52
|
"2024.10": "pip wheel uv",
|
|
50
53
|
"2024.04": "pip wheel uv",
|
|
@@ -260,26 +260,35 @@ async def list_(*, json: bool = False, env: Optional[str] = None):
|
|
|
260
260
|
@click.option(
|
|
261
261
|
"--name",
|
|
262
262
|
default=None,
|
|
263
|
-
help="Endpoint name.
|
|
263
|
+
help="Endpoint name. If omitted, Modal chooses a name.",
|
|
264
264
|
)
|
|
265
265
|
@click.option(
|
|
266
266
|
"--model",
|
|
267
267
|
required=True,
|
|
268
268
|
help="Hugging Face repo ID for the base model architecture (e.g., 'Qwen/Qwen3.6-27B-FP8').",
|
|
269
269
|
)
|
|
270
|
+
@click.option(
|
|
271
|
+
"--shared",
|
|
272
|
+
is_flag=True,
|
|
273
|
+
default=False,
|
|
274
|
+
help="Create a Shared Endpoint. Defaults to a Dedicated Endpoint.",
|
|
275
|
+
)
|
|
270
276
|
@click.option(
|
|
271
277
|
"--routing-region",
|
|
272
278
|
"routing_region",
|
|
273
279
|
multiple=True,
|
|
274
280
|
callback=_single_routing_region_callback,
|
|
275
|
-
help=
|
|
281
|
+
help=(
|
|
282
|
+
f"Region to route inference requests through. Defaults to {_DEFAULT_ROUTING_REGION}. "
|
|
283
|
+
"Shared Endpoint routing cannot currently be customized."
|
|
284
|
+
),
|
|
276
285
|
)
|
|
277
286
|
@click.option(
|
|
278
287
|
"--compute-region",
|
|
279
288
|
"compute_regions",
|
|
280
289
|
multiple=True,
|
|
281
290
|
help=(
|
|
282
|
-
"Region to run Endpoint containers in. May be specified multiple times. "
|
|
291
|
+
"Region to run Dedicated Endpoint containers in. May be specified multiple times. "
|
|
283
292
|
"This incurs a region selection price multiplier."
|
|
284
293
|
),
|
|
285
294
|
)
|
|
@@ -287,13 +296,16 @@ async def list_(*, json: bool = False, env: Optional[str] = None):
|
|
|
287
296
|
"--colocate-compute",
|
|
288
297
|
is_flag=True,
|
|
289
298
|
default=False,
|
|
290
|
-
help=
|
|
299
|
+
help=(
|
|
300
|
+
"Run all Dedicated Endpoint containers within the routing region. "
|
|
301
|
+
"This incurs a region selection price multiplier."
|
|
302
|
+
),
|
|
291
303
|
)
|
|
292
304
|
@click.option(
|
|
293
305
|
"--unauthenticated",
|
|
294
306
|
is_flag=True,
|
|
295
307
|
default=False,
|
|
296
|
-
help="Allow unauthenticated HTTP requests to
|
|
308
|
+
help="Allow unauthenticated HTTP requests to a Dedicated Endpoint.",
|
|
297
309
|
)
|
|
298
310
|
@click.option("--custom-hf-repo", default=None, help="Hugging Face repo ID for fine-tuned model weights.")
|
|
299
311
|
@click.option("--custom-hf-revision", default=None, help="Git revision for --custom-hf-repo.")
|
|
@@ -304,6 +316,7 @@ async def list_(*, json: bool = False, env: Optional[str] = None):
|
|
|
304
316
|
async def create(
|
|
305
317
|
name: Optional[str],
|
|
306
318
|
model: Optional[str] = None,
|
|
319
|
+
shared: bool = False,
|
|
307
320
|
routing_region: str = _DEFAULT_ROUTING_REGION,
|
|
308
321
|
compute_regions: tuple[str, ...] = (),
|
|
309
322
|
colocate_compute: bool = False,
|
|
@@ -317,13 +330,21 @@ async def create(
|
|
|
317
330
|
):
|
|
318
331
|
"""Deploy a new Endpoint.
|
|
319
332
|
|
|
333
|
+
Creates a Dedicated Endpoint by default, with support for custom weights and compute placement.
|
|
334
|
+
Use --shared to serve a supported base model with Modal-managed capacity.
|
|
335
|
+
|
|
320
336
|
Examples:
|
|
321
337
|
|
|
322
|
-
Create
|
|
338
|
+
Create a Dedicated Endpoint from a base model:
|
|
323
339
|
```bash
|
|
324
340
|
modal endpoint create --model Qwen/Qwen3.6-27B-FP8
|
|
325
341
|
```
|
|
326
342
|
|
|
343
|
+
Create a Shared Endpoint from a supported base model:
|
|
344
|
+
```bash
|
|
345
|
+
modal endpoint create --shared --model moonshotai/Kimi-K3
|
|
346
|
+
```
|
|
347
|
+
|
|
327
348
|
Create an Endpoint with an explicit name:
|
|
328
349
|
```bash
|
|
329
350
|
modal endpoint create --name qwen-chat --model Qwen/Qwen3.6-27B-FP8
|
|
@@ -348,6 +369,22 @@ async def create(
|
|
|
348
369
|
```
|
|
349
370
|
|
|
350
371
|
"""
|
|
372
|
+
if shared:
|
|
373
|
+
for option, provided in (
|
|
374
|
+
("--compute-region", bool(compute_regions)),
|
|
375
|
+
("--colocate-compute", colocate_compute),
|
|
376
|
+
("--unauthenticated", unauthenticated),
|
|
377
|
+
("--custom-hf-repo", custom_hf_repo is not None),
|
|
378
|
+
("--custom-hf-revision", custom_hf_revision is not None),
|
|
379
|
+
("--custom-hf-token", custom_hf_token is not None),
|
|
380
|
+
("--custom-volume-name", custom_volume_name is not None),
|
|
381
|
+
("--custom-volume-path", custom_volume_path is not None),
|
|
382
|
+
):
|
|
383
|
+
if provided:
|
|
384
|
+
raise click.UsageError(f"{option} cannot be used with --shared.")
|
|
385
|
+
if routing_region != _DEFAULT_ROUTING_REGION:
|
|
386
|
+
raise click.UsageError(f"Shared Endpoints require --routing-region {_DEFAULT_ROUTING_REGION}.")
|
|
387
|
+
|
|
351
388
|
if compute_regions and colocate_compute:
|
|
352
389
|
raise click.UsageError("--compute-region and --colocate-compute are mutually exclusive.")
|
|
353
390
|
if custom_hf_repo and custom_volume_name:
|
|
@@ -403,13 +440,18 @@ async def create(
|
|
|
403
440
|
model=model_source,
|
|
404
441
|
environment_name=environment_name,
|
|
405
442
|
unauthenticated=unauthenticated,
|
|
443
|
+
serving_mode=(api_pb2.ENDPOINT_SERVING_MODE_SHARED if shared else api_pb2.ENDPOINT_SERVING_MODE_DEDICATED),
|
|
406
444
|
)
|
|
407
445
|
if name:
|
|
408
446
|
req.name = name
|
|
409
447
|
resp = await client._stub.EndpointCreate(req)
|
|
410
448
|
|
|
411
449
|
output = OutputManager.get()
|
|
412
|
-
|
|
450
|
+
serving_mode = "Shared" if shared else "Dedicated"
|
|
451
|
+
output.print(
|
|
452
|
+
f"[green]✓[/green] {serving_mode} Endpoint '{resp.name}' ({resp.endpoint_id}) "
|
|
453
|
+
"was created and started provisioning."
|
|
454
|
+
)
|
|
413
455
|
if resp.model_name:
|
|
414
456
|
output.print(f' → Send [cyan]"model": "{resp.model_name}"[/cyan] in requests to the Endpoint.')
|
|
415
457
|
if resp.endpoint_page_url:
|
|
@@ -33,7 +33,7 @@ async def list_(json: bool | None = False):
|
|
|
33
33
|
profiles = config_profiles()
|
|
34
34
|
lookup_coros = [
|
|
35
35
|
_lookup_workspace(
|
|
36
|
-
config.get("server_url", profile=profile),
|
|
36
|
+
config.get("server_url", profile=profile, use_env=False),
|
|
37
37
|
token_id=config.get("token_id", profile=profile, use_env=False),
|
|
38
38
|
token_secret=config.get("token_secret", profile=profile, use_env=False),
|
|
39
39
|
oauth_refresh_token=config.get("oauth_refresh_token", profile=profile, use_env=False),
|
|
@@ -471,7 +471,7 @@ def service_users_list(json: bool):
|
|
|
471
471
|
|
|
472
472
|
@service_users_cli.command("delete", no_args_is_help=True)
|
|
473
473
|
@click.argument("name")
|
|
474
|
-
@click.option("--allow-missing", is_flag=True, default=False, help="Don't error if the
|
|
474
|
+
@click.option("--allow-missing", is_flag=True, default=False, help="Don't error if the Service User doesn't exist.")
|
|
475
475
|
@yes_option
|
|
476
476
|
def service_users_delete(name: str, *, allow_missing: bool, yes: bool):
|
|
477
477
|
"""Delete a Service User in this Workspace.
|
|
@@ -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.
|
|
90
|
+
version: str = "1.6.4.dev0",
|
|
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.
|
|
307
|
+
version: str = "1.6.4.dev0",
|
|
308
308
|
*,
|
|
309
309
|
oauth_credentials: typing.Optional[_OAuthCredentials] = None,
|
|
310
310
|
):
|
|
@@ -65,7 +65,8 @@ class Image(modal.object.Object):
|
|
|
65
65
|
base_images: typing.Optional[dict[str, Image]] = None,
|
|
66
66
|
dockerfile_function: typing.Optional[
|
|
67
67
|
collections.abc.Callable[
|
|
68
|
-
[typing.Literal["2023.12", "2024.04", "2024.10", "2025.06", "PREVIEW"]],
|
|
68
|
+
[typing.Literal["2023.12", "2024.04", "2024.10", "2025.06", "2026.10", "PREVIEW"]],
|
|
69
|
+
modal._image.DockerfileSpec,
|
|
69
70
|
]
|
|
70
71
|
] = None,
|
|
71
72
|
secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
|
|
@@ -75,7 +76,7 @@ class Image(modal.object.Object):
|
|
|
75
76
|
image_registry_config: typing.Optional[modal._image._ImageRegistryConfig] = None,
|
|
76
77
|
context_mount_function: typing.Optional[
|
|
77
78
|
collections.abc.Callable[
|
|
78
|
-
[typing.Literal["2023.12", "2024.04", "2024.10", "2025.06", "PREVIEW"]],
|
|
79
|
+
[typing.Literal["2023.12", "2024.04", "2024.10", "2025.06", "2026.10", "PREVIEW"]],
|
|
79
80
|
typing.Optional[modal.mount.Mount],
|
|
80
81
|
]
|
|
81
82
|
] = None,
|
|
@@ -873,7 +874,7 @@ class Image(modal.object.Object):
|
|
|
873
874
|
@staticmethod
|
|
874
875
|
def _registry_setup_commands(
|
|
875
876
|
tag: str,
|
|
876
|
-
builder_version: typing.Literal["2023.12", "2024.04", "2024.10", "2025.06", "PREVIEW"],
|
|
877
|
+
builder_version: typing.Literal["2023.12", "2024.04", "2024.10", "2025.06", "2026.10", "PREVIEW"],
|
|
877
878
|
setup_commands: list[str],
|
|
878
879
|
add_python: typing.Optional[str] = None,
|
|
879
880
|
) -> list[str]: ...
|
|
@@ -945,7 +946,11 @@ class Image(modal.object.Object):
|
|
|
945
946
|
add_python: typing.Optional[str] = None,
|
|
946
947
|
**kwargs,
|
|
947
948
|
) -> Image:
|
|
948
|
-
"""
|
|
949
|
+
"""mdmd:hidden
|
|
950
|
+
Build a Modal image from a private image in Google Cloud Platform (GCP) Artifact Registry.
|
|
951
|
+
|
|
952
|
+
**Note:** This constructor is superseded by `Image.from_registry()`, which can also authenticate
|
|
953
|
+
to private repositories when provided with the appropriate keys in a `modal.Secret`.
|
|
949
954
|
|
|
950
955
|
You will need to pass a `modal.Secret` containing [your GCP service account key data](https://cloud.google.com/iam/docs/keys-create-delete#creating)
|
|
951
956
|
as `SERVICE_ACCOUNT_JSON`. This can be done from the [Secrets](https://modal.com/secrets) page.
|
|
@@ -996,11 +1001,15 @@ class Image(modal.object.Object):
|
|
|
996
1001
|
add_python: typing.Optional[str] = None,
|
|
997
1002
|
**kwargs,
|
|
998
1003
|
) -> Image:
|
|
999
|
-
"""
|
|
1004
|
+
"""mdmd:hidden
|
|
1005
|
+
Build a Modal image from a private image in AWS Elastic Container Registry (ECR).
|
|
1000
1006
|
|
|
1001
1007
|
You will need to pass a `modal.Secret` containing either IAM user credentials or OIDC
|
|
1002
1008
|
configuration to access the target ECR registry.
|
|
1003
1009
|
|
|
1010
|
+
**Note:** This constructor is superseded by `Image.from_registry()`, which can also authenticate
|
|
1011
|
+
to private repositories when provided with the appropriate keys in a `modal.Secret`.
|
|
1012
|
+
|
|
1004
1013
|
For IAM user authentication, set `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and `AWS_REGION`.
|
|
1005
1014
|
|
|
1006
1015
|
For OIDC authentication, set `AWS_ROLE_ARN` and `AWS_REGION`.
|
|
@@ -1043,30 +1052,35 @@ class Image(modal.object.Object):
|
|
|
1043
1052
|
*,
|
|
1044
1053
|
force_build: bool = False,
|
|
1045
1054
|
context_dir: typing.Union[pathlib.Path, str, None] = None,
|
|
1046
|
-
env: typing.Optional[dict[str, typing.Optional[str]]] = None,
|
|
1047
|
-
secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
|
|
1048
|
-
gpu: typing.Optional[str] = None,
|
|
1049
|
-
add_python: typing.Optional[str] = None,
|
|
1050
|
-
build_args: dict[str, str] = {},
|
|
1051
1055
|
ignore: typing.Union[
|
|
1052
1056
|
collections.abc.Sequence[str], collections.abc.Callable[[pathlib.Path], bool]
|
|
1053
1057
|
] = modal._image.AUTO_DOCKERIGNORE,
|
|
1058
|
+
build_args: dict[str, str] = {},
|
|
1059
|
+
registry_secret: typing.Optional[modal.secret.Secret] = None,
|
|
1060
|
+
secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
|
|
1061
|
+
env: typing.Optional[dict[str, typing.Optional[str]]] = None,
|
|
1062
|
+
gpu: typing.Optional[str] = None,
|
|
1063
|
+
add_python: typing.Optional[str] = None,
|
|
1054
1064
|
) -> Image:
|
|
1055
1065
|
"""Build a Modal image from a local Dockerfile.
|
|
1056
1066
|
|
|
1057
1067
|
If your Dockerfile does not have Python installed, you can use the `add_python` parameter
|
|
1058
1068
|
to specify a version of Python to add to the image.
|
|
1059
1069
|
|
|
1070
|
+
A `registry_secret` can be provided to pull the base image from a private registry.
|
|
1071
|
+
Currently this is supported only for single-stage Dockerfiles.
|
|
1072
|
+
|
|
1060
1073
|
Args:
|
|
1061
1074
|
path: Path to the Dockerfile on the local machine.
|
|
1062
1075
|
force_build: If True, skip cached image builds.
|
|
1063
1076
|
context_dir: Build context directory for resolving relative COPY paths.
|
|
1077
|
+
ignore: Ignore rules for the implicit context mount (defaults to auto ``.dockerignore`` behavior).
|
|
1078
|
+
build_args: Dockerfile ``ARG`` values forwarded to the build.
|
|
1079
|
+
registry_secret: Optional Secret with credentials for pulling the base image from a private registry.
|
|
1080
|
+
secrets: Secrets injected as environment variables in the build container.
|
|
1064
1081
|
env: Environment variables set in the build container.
|
|
1065
|
-
|
|
1066
|
-
gpu: GPU type to attach to the builder container.
|
|
1082
|
+
gpu: GPU type to attach to the build container.
|
|
1067
1083
|
add_python: Standalone Python version to add when the Dockerfile does not install Python.
|
|
1068
|
-
build_args: Dockerfile ``ARG`` values forwarded to the build.
|
|
1069
|
-
ignore: Ignore rules for the implicit context mount (defaults to auto ``.dockerignore`` behavior).
|
|
1070
1084
|
|
|
1071
1085
|
Returns:
|
|
1072
1086
|
An `Image` built from the Dockerfile plus Modal runtime dependencies.
|
|
@@ -1112,6 +1126,12 @@ class Image(modal.object.Object):
|
|
|
1112
1126
|
add_python="3.12",
|
|
1113
1127
|
ignore=FilePatternMatcher.from_file("/path/to/dockerignore"),
|
|
1114
1128
|
)
|
|
1129
|
+
|
|
1130
|
+
# Pull the Dockerfile's base image from a private registry.
|
|
1131
|
+
image = modal.Image.from_dockerfile(
|
|
1132
|
+
"./Dockerfile",
|
|
1133
|
+
registry_secret=modal.Secret.from_name("my-registry-secret"),
|
|
1134
|
+
)
|
|
1115
1135
|
```
|
|
1116
1136
|
"""
|
|
1117
1137
|
...
|
|
@@ -369,36 +369,48 @@ class _StreamReaderThroughCommandRouterBase(_StreamReaderImpl[T]):
|
|
|
369
369
|
"""Open the underlying stream at the current offset."""
|
|
370
370
|
raise NotImplementedError
|
|
371
371
|
|
|
372
|
+
def _current_stream(self) -> AsyncGenerator[T, None]:
|
|
373
|
+
if self._stream is None:
|
|
374
|
+
self._stream = self._iterate_stream()
|
|
375
|
+
return self._stream
|
|
376
|
+
|
|
372
377
|
async def __anext__(self) -> T:
|
|
373
378
|
async with self._lock:
|
|
374
|
-
|
|
375
|
-
self._stream = self._iterate_stream()
|
|
376
|
-
return await self._stream.__anext__()
|
|
379
|
+
return await self._current_stream().__anext__()
|
|
377
380
|
|
|
378
381
|
async def _consume_stream(self) -> AsyncGenerator[T, None]:
|
|
382
|
+
# An iterator abandoned mid-loop is finalized at an arbitrary later
|
|
383
|
+
# time, so it must only close the stream it pulled from, never one a
|
|
384
|
+
# later iterator has since reopened.
|
|
385
|
+
stream: AsyncGenerator[T, None] | None = None
|
|
379
386
|
try:
|
|
380
387
|
while True:
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
388
|
+
async with self._lock:
|
|
389
|
+
stream = self._current_stream()
|
|
390
|
+
try:
|
|
391
|
+
item = await stream.__anext__()
|
|
392
|
+
except StopAsyncIteration:
|
|
393
|
+
return
|
|
385
394
|
yield item
|
|
386
395
|
finally:
|
|
387
|
-
await self.
|
|
396
|
+
await self._close_stream(stream)
|
|
388
397
|
|
|
389
398
|
def __aiter__(self) -> AsyncGenerator[T, None]:
|
|
390
399
|
return self._consume_stream()
|
|
391
400
|
|
|
392
|
-
async def
|
|
393
|
-
|
|
394
|
-
pulling from is left open for that reader to close."""
|
|
395
|
-
if self._lock.locked():
|
|
401
|
+
async def _close_stream(self, stream: AsyncGenerator[T, None] | None) -> None:
|
|
402
|
+
if stream is None or self._lock.locked():
|
|
396
403
|
return
|
|
397
404
|
async with self._lock:
|
|
398
|
-
|
|
399
|
-
|
|
405
|
+
if self._stream is stream:
|
|
406
|
+
self._stream = None
|
|
400
407
|
await stream.aclose()
|
|
401
408
|
|
|
409
|
+
async def aclose(self) -> None:
|
|
410
|
+
"""Close the underlying stream. A stream another reader is currently
|
|
411
|
+
pulling from is left open for that reader to close."""
|
|
412
|
+
await self._close_stream(self._stream)
|
|
413
|
+
|
|
402
414
|
|
|
403
415
|
class _BytesStreamReaderThroughCommandRouter(_StreamReaderThroughCommandRouterBase[bytes]):
|
|
404
416
|
"""StreamReader that yields raw bytes from the router-backed stdio source
|
|
@@ -243,9 +243,11 @@ class _StreamReaderThroughCommandRouterBase(_StreamReaderImpl[T]):
|
|
|
243
243
|
"""Open the underlying stream at the current offset."""
|
|
244
244
|
...
|
|
245
245
|
|
|
246
|
+
def _current_stream(self) -> collections.abc.AsyncGenerator[T, None]: ...
|
|
246
247
|
async def __anext__(self) -> T: ...
|
|
247
248
|
def _consume_stream(self) -> collections.abc.AsyncGenerator[T, None]: ...
|
|
248
249
|
def __aiter__(self) -> collections.abc.AsyncGenerator[T, None]: ...
|
|
250
|
+
async def _close_stream(self, stream: typing.Optional[collections.abc.AsyncGenerator[T, None]]) -> None: ...
|
|
249
251
|
async def aclose(self) -> None:
|
|
250
252
|
"""Close the underlying stream. A stream another reader is currently
|
|
251
253
|
pulling from is left open for that reader to close.
|
|
@@ -63,6 +63,15 @@ PYTHON_STANDALONE_VERSIONS: dict[str, dict[str, tuple[str, str]]] = {
|
|
|
63
63
|
"3.15": ("20261021", "3.15.1"),
|
|
64
64
|
"3.15t": ("20261021", "3.15.1t"),
|
|
65
65
|
},
|
|
66
|
+
"2026.10": {
|
|
67
|
+
"3.11": ("20261021", "3.11.17"),
|
|
68
|
+
"3.12": ("20261021", "3.12.15"),
|
|
69
|
+
"3.13": ("20261021", "3.13.17"),
|
|
70
|
+
"3.14": ("20261021", "3.14.9"),
|
|
71
|
+
"3.14t": ("20261021", "3.14.9t"),
|
|
72
|
+
"3.15": ("20261021", "3.15.1"),
|
|
73
|
+
"3.15t": ("20261021", "3.15.1t"),
|
|
74
|
+
},
|
|
66
75
|
"2025.06": _PYTHON_STANDALONE_VERSIONS_2025_06,
|
|
67
76
|
"2024.10": _PYTHON_STANDALONE_VERSIONS_2025_06,
|
|
68
77
|
"2024.04": _PYTHON_STANDALONE_VERSIONS_2025_06,
|