modal 1.4.4.dev20__tar.gz → 1.4.4.dev21__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.
Files changed (224) hide show
  1. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/PKG-INFO +1 -1
  2. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_functions.py +28 -9
  3. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_server.py +10 -2
  4. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/app.py +4 -4
  5. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/app.pyi +2 -2
  6. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/cli/entry_point.py +2 -0
  7. modal-1.4.4.dev21/modal/cli/image.py +110 -0
  8. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/client.pyi +2 -2
  9. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/functions.pyi +32 -10
  10. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/server.pyi +16 -2
  11. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal.egg-info/PKG-INFO +1 -1
  12. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal.egg-info/SOURCES.txt +1 -0
  13. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal_docs/gen_cli_docs.py +11 -5
  14. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal_proto/api_grpc.py +32 -0
  15. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal_proto/api_pb2.py +879 -810
  16. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal_proto/api_pb2.pyi +173 -8
  17. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal_proto/api_pb2_grpc.py +66 -0
  18. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal_proto/api_pb2_grpc.pyi +20 -0
  19. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal_proto/modal_api_grpc.py +2 -0
  20. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal_version/__init__.py +1 -1
  21. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/LICENSE +0 -0
  22. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/README.md +0 -0
  23. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/__init__.py +0 -0
  24. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/__main__.py +0 -0
  25. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_billing.py +0 -0
  26. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_clustered_functions.py +0 -0
  27. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_clustered_functions.pyi +0 -0
  28. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_container_entrypoint.py +0 -0
  29. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_environments.py +0 -0
  30. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_function_variants.py +0 -0
  31. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_grpc_client.py +0 -0
  32. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_image.py +0 -0
  33. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_ipython.py +0 -0
  34. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_load_context.py +0 -0
  35. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_location.py +0 -0
  36. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_logs.py +0 -0
  37. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_object.py +0 -0
  38. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_output/__init__.py +0 -0
  39. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_output/manager.py +0 -0
  40. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_output/pty.py +0 -0
  41. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_output/rich.py +0 -0
  42. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_output/status.py +0 -0
  43. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_partial_function.py +0 -0
  44. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_resolver.py +0 -0
  45. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_resources.py +0 -0
  46. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_runtime/__init__.py +0 -0
  47. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_runtime/asgi.py +0 -0
  48. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_runtime/container_io_manager.py +0 -0
  49. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_runtime/container_io_manager.pyi +0 -0
  50. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_runtime/execution_context.py +0 -0
  51. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_runtime/execution_context.pyi +0 -0
  52. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_runtime/gpu_memory_snapshot.py +0 -0
  53. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_runtime/task_lifecycle_manager.py +0 -0
  54. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_runtime/task_lifecycle_manager.pyi +0 -0
  55. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_runtime/telemetry.py +0 -0
  56. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_runtime/user_code_event_loop.py +0 -0
  57. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_runtime/user_code_imports.py +0 -0
  58. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_serialization.py +0 -0
  59. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_traceback.py +0 -0
  60. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_tunnel.py +0 -0
  61. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_tunnel.pyi +0 -0
  62. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_type_manager.py +0 -0
  63. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_utils/__init__.py +0 -0
  64. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_utils/app_utils.py +0 -0
  65. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_utils/async_utils.py +0 -0
  66. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_utils/auth_token_manager.py +0 -0
  67. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_utils/blob_utils.py +0 -0
  68. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_utils/browser_utils.py +0 -0
  69. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_utils/bytes_io_segment_payload.py +0 -0
  70. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_utils/deprecation.py +0 -0
  71. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_utils/docker_utils.py +0 -0
  72. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_utils/function_utils.py +0 -0
  73. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_utils/git_utils.py +0 -0
  74. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_utils/grpc_testing.py +0 -0
  75. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_utils/grpc_utils.py +0 -0
  76. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_utils/hash_utils.py +0 -0
  77. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_utils/http_utils.py +0 -0
  78. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_utils/jwt_utils.py +0 -0
  79. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_utils/logger.py +0 -0
  80. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_utils/mount_utils.py +0 -0
  81. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_utils/name_utils.py +0 -0
  82. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_utils/package_utils.py +0 -0
  83. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_utils/pattern_utils.py +0 -0
  84. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_utils/rand_pb_testing.py +0 -0
  85. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_utils/sandbox_fs_utils.py +0 -0
  86. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_utils/shell_utils.py +0 -0
  87. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_utils/task_command_router_client.py +0 -0
  88. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_utils/time_utils.py +0 -0
  89. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_vendor/__init__.py +0 -0
  90. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_vendor/a2wsgi_wsgi.py +0 -0
  91. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_vendor/cloudpickle.py +0 -0
  92. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_vendor/tblib.py +0 -0
  93. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_vendor/version.py +0 -0
  94. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_watcher.py +0 -0
  95. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/_workspace.py +0 -0
  96. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/billing.py +0 -0
  97. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/builder/2023.12.312.txt +0 -0
  98. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/builder/2023.12.txt +0 -0
  99. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/builder/2024.04.txt +0 -0
  100. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/builder/2024.10.txt +0 -0
  101. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/builder/2025.06.txt +0 -0
  102. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/builder/PREVIEW.txt +0 -0
  103. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/builder/README.md +0 -0
  104. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/builder/base-images.json +0 -0
  105. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/call_graph.py +0 -0
  106. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/cli/__init__.py +0 -0
  107. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/cli/_download.py +0 -0
  108. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/cli/_help.py +0 -0
  109. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/cli/_traceback.py +0 -0
  110. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/cli/app.py +0 -0
  111. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/cli/billing.py +0 -0
  112. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/cli/bootstrap.py +0 -0
  113. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/cli/changelog.py +0 -0
  114. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/cli/cluster.py +0 -0
  115. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/cli/config.py +0 -0
  116. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/cli/container.py +0 -0
  117. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/cli/dashboard.py +0 -0
  118. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/cli/dict.py +0 -0
  119. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/cli/environment.py +0 -0
  120. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/cli/import_refs.py +0 -0
  121. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/cli/launch.py +0 -0
  122. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/cli/logo.py +0 -0
  123. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/cli/network_file_system.py +0 -0
  124. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/cli/profile.py +0 -0
  125. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/cli/programs/__init__.py +0 -0
  126. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/cli/programs/run_jupyter.py +0 -0
  127. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/cli/programs/vscode.py +0 -0
  128. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/cli/queues.py +0 -0
  129. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/cli/run.py +0 -0
  130. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/cli/secret.py +0 -0
  131. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/cli/selector.py +0 -0
  132. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/cli/shell.py +0 -0
  133. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/cli/skills.py +0 -0
  134. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/cli/token.py +0 -0
  135. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/cli/utils.py +0 -0
  136. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/cli/volume.py +0 -0
  137. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/client.py +0 -0
  138. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/cloud_bucket_mount.py +0 -0
  139. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/cloud_bucket_mount.pyi +0 -0
  140. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/cls.py +0 -0
  141. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/cls.pyi +0 -0
  142. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/config.py +0 -0
  143. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/container_process.py +0 -0
  144. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/container_process.pyi +0 -0
  145. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/dict.py +0 -0
  146. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/dict.pyi +0 -0
  147. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/environments.py +0 -0
  148. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/environments.pyi +0 -0
  149. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/exception.py +0 -0
  150. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/experimental/__init__.py +0 -0
  151. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/experimental/flash.py +0 -0
  152. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/experimental/flash.pyi +0 -0
  153. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/experimental/ipython.py +0 -0
  154. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/file_io.py +0 -0
  155. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/file_io.pyi +0 -0
  156. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/file_pattern_matcher.py +0 -0
  157. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/functions.py +0 -0
  158. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/image.py +0 -0
  159. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/image.pyi +0 -0
  160. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/io_streams.py +0 -0
  161. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/io_streams.pyi +0 -0
  162. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/mount.py +0 -0
  163. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/mount.pyi +0 -0
  164. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/network_file_system.py +0 -0
  165. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/network_file_system.pyi +0 -0
  166. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/object.py +0 -0
  167. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/object.pyi +0 -0
  168. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/output.py +0 -0
  169. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/parallel_map.py +0 -0
  170. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/parallel_map.pyi +0 -0
  171. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/partial_function.py +0 -0
  172. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/partial_function.pyi +0 -0
  173. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/proxy.py +0 -0
  174. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/proxy.pyi +0 -0
  175. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/py.typed +0 -0
  176. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/queue.py +0 -0
  177. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/queue.pyi +0 -0
  178. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/retries.py +0 -0
  179. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/runner.py +0 -0
  180. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/runner.pyi +0 -0
  181. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/running_app.py +0 -0
  182. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/sandbox.py +0 -0
  183. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/sandbox.pyi +0 -0
  184. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/sandbox_fs.py +0 -0
  185. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/sandbox_fs.pyi +0 -0
  186. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/schedule.py +0 -0
  187. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/scheduler_placement.py +0 -0
  188. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/secret.py +0 -0
  189. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/secret.pyi +0 -0
  190. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/server.py +0 -0
  191. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/serving.py +0 -0
  192. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/serving.pyi +0 -0
  193. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/skills/modal/SKILL.md +0 -0
  194. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/snapshot.py +0 -0
  195. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/snapshot.pyi +0 -0
  196. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/stream_type.py +0 -0
  197. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/token_flow.py +0 -0
  198. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/token_flow.pyi +0 -0
  199. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/volume.py +0 -0
  200. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/volume.pyi +0 -0
  201. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/workspace.py +0 -0
  202. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal/workspace.pyi +0 -0
  203. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal.egg-info/dependency_links.txt +0 -0
  204. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal.egg-info/entry_points.txt +0 -0
  205. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal.egg-info/requires.txt +0 -0
  206. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal.egg-info/top_level.txt +0 -0
  207. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal_docs/__init__.py +0 -0
  208. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal_docs/gen_cli_docs_main.py +0 -0
  209. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal_docs/gen_reference_docs.py +0 -0
  210. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal_docs/gen_reference_docs_main.py +0 -0
  211. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal_docs/mdmd/__init__.py +0 -0
  212. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal_docs/mdmd/mdmd.py +0 -0
  213. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal_docs/mdmd/signatures.py +0 -0
  214. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal_docs/mdmd/types.py +0 -0
  215. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal_proto/__init__.py +0 -0
  216. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal_proto/py.typed +0 -0
  217. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal_proto/task_command_router_grpc.py +0 -0
  218. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal_proto/task_command_router_pb2.py +0 -0
  219. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal_proto/task_command_router_pb2.pyi +0 -0
  220. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal_proto/task_command_router_pb2_grpc.py +0 -0
  221. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal_proto/task_command_router_pb2_grpc.pyi +0 -0
  222. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/modal_version/__main__.py +0 -0
  223. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/pyproject.toml +0 -0
  224. {modal-1.4.4.dev20 → modal-1.4.4.dev21}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.4.4.dev20
3
+ Version: 1.4.4.dev21
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License-Expression: Apache-2.0
@@ -934,7 +934,9 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
934
934
  if app and app.name:
935
935
  app_name = app.name
936
936
 
937
- # on builder > 2024.10 we mount client dependencies at runtime
937
+ # TODO: client-side `mount_client_dependencies` can be removed after 2026-06-15
938
+ # Kept so that the function definition proto stays identical across deploys
939
+ # (removing it would change the proto, creating a new app version)
938
940
  mount_client_dependencies = False
939
941
  if image._metadata is not None:
940
942
  mount_client_dependencies = image._metadata.image_builder_version > "2024.10"
@@ -1149,6 +1151,28 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
1149
1151
 
1150
1152
  return obj
1151
1153
 
1154
+ async def _update_autoscaler(
1155
+ self,
1156
+ *,
1157
+ min_containers: int | None = None,
1158
+ max_containers: int | None = None,
1159
+ buffer_containers: int | None = None,
1160
+ scaledown_window: int | None = None,
1161
+ target_concurrency: int | None = None,
1162
+ ) -> None:
1163
+ settings = api_pb2.AutoscalerSettings(
1164
+ min_containers=min_containers,
1165
+ max_containers=max_containers,
1166
+ buffer_containers=buffer_containers,
1167
+ scaledown_window=scaledown_window,
1168
+ target_concurrency=target_concurrency,
1169
+ )
1170
+ request = api_pb2.FunctionUpdateSchedulingParamsRequest(function_id=self.object_id, settings=settings)
1171
+ await self.client.stub.FunctionUpdateSchedulingParams(request)
1172
+
1173
+ # One idea would be for FunctionUpdateScheduleParams to return the current (coalesced) settings
1174
+ # and then we could return them here (would need some ad hoc dataclass, which I don't love)
1175
+
1152
1176
  @live_method
1153
1177
  async def update_autoscaler(
1154
1178
  self,
@@ -1184,24 +1208,19 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
1184
1208
 
1185
1209
  # Extend the scaledown window to increase the amount of time that idle containers stay alive
1186
1210
  f.update_autoscaler(scaledown_window=300)
1187
-
1188
- ```
1211
+ ```
1189
1212
 
1190
1213
  """
1214
+ # Assert .update_autoscaler() is not called on a method as opposed to the Object. Applicable for Cls only.
1191
1215
  if self._is_method:
1192
1216
  raise InvalidError("Cannot call .update_autoscaler() on a method. Call it on the class instance instead.")
1193
1217
 
1194
- settings = api_pb2.AutoscalerSettings(
1218
+ await self._update_autoscaler(
1195
1219
  min_containers=min_containers,
1196
1220
  max_containers=max_containers,
1197
1221
  buffer_containers=buffer_containers,
1198
1222
  scaledown_window=scaledown_window,
1199
1223
  )
1200
- request = api_pb2.FunctionUpdateSchedulingParamsRequest(function_id=self.object_id, settings=settings)
1201
- await self.client.stub.FunctionUpdateSchedulingParams(request)
1202
-
1203
- # One idea would be for FunctionUpdateScheduleParams to return the current (coalesced) settings
1204
- # and then we could return them here (would need some ad hoc dataclass, which I don't love)
1205
1224
 
1206
1225
  @classmethod
1207
1226
  def _from_name(
@@ -100,6 +100,7 @@ class _Server:
100
100
  max_containers: int | None = None,
101
101
  buffer_containers: int | None = None,
102
102
  scaledown_window: int | None = None,
103
+ target_concurrency: int | None = None,
103
104
  ) -> None:
104
105
  """Override the current autoscaler behavior for this Server.
105
106
 
@@ -114,14 +115,21 @@ class _Server:
114
115
 
115
116
  # Limit this Server to avoid spinning up more than 5 containers
116
117
  server.update_autoscaler(max_containers=5)
117
- ```
118
+
119
+ # Adjust Server autoscaling to target 20 concurrent requests per replica
120
+ server.update_autoscaler(target_concurrency=20)
121
+
122
+ # Disable the Server autoscaling by setting target_concurrency to 0
123
+ server.update_autoscaler(target_concurrency=0)
124
+ ```
118
125
 
119
126
  """
120
- return await self._get_service_function().update_autoscaler(
127
+ return await self._get_service_function()._update_autoscaler(
121
128
  min_containers=min_containers,
122
129
  max_containers=max_containers,
123
130
  scaledown_window=scaledown_window,
124
131
  buffer_containers=buffer_containers,
132
+ target_concurrency=target_concurrency,
125
133
  )
126
134
 
127
135
  # ============ Hydration ============
@@ -1291,7 +1291,7 @@ class _App:
1291
1291
  exit_grace_period: int = 0, # Grace period for in-flight requests on shutdown
1292
1292
  routing_regions: list[str] = ["us-east"], # Required: Regions to deploy proxy endpoints
1293
1293
  h2_enabled: bool = False, # Enable HTTP/2
1294
- target_concurrency: int | None = None, # Target concurrency for the server
1294
+ target_concurrency: int | None = None, # Target concurrency for the server; 0 disables autoscaling
1295
1295
  cloud: str | None = None, # Cloud provider (aws, gcp, oci, auto)
1296
1296
  region: str | Sequence[str] | None = None, # Region(s) to run on
1297
1297
  nonpreemptible: bool = False, # Whether to use non-preemptible instances
@@ -1333,7 +1333,7 @@ class _App:
1333
1333
  exit_grace_period: Grace period for in-flight requests on shutdown.
1334
1334
  routing_regions: Regions to deploy proxy endpoints.
1335
1335
  h2_enabled: Enable HTTP/2.
1336
- target_concurrency: Target concurrency for the server.
1336
+ target_concurrency: Target concurrency for the server; 0 disables autoscaling.
1337
1337
  cloud: Cloud provider (aws, gcp, oci, auto).
1338
1338
  region: Region(s) to run on.
1339
1339
  nonpreemptible: Whether to use non-preemptible instances.
@@ -1368,8 +1368,8 @@ class _App:
1368
1368
  )
1369
1369
 
1370
1370
  if target_concurrency is not None:
1371
- if not isinstance(target_concurrency, int) or target_concurrency < 1:
1372
- raise InvalidError("The `target_concurrency` argument must be a positive integer.")
1371
+ if not isinstance(target_concurrency, int) or target_concurrency < 0:
1372
+ raise InvalidError("The `target_concurrency` argument must be a non-negative integer.")
1373
1373
 
1374
1374
  http_config = api_pb2.HTTPConfig(
1375
1375
  port=port,
@@ -796,7 +796,7 @@ class _App:
796
796
  exit_grace_period: Grace period for in-flight requests on shutdown.
797
797
  routing_regions: Regions to deploy proxy endpoints.
798
798
  h2_enabled: Enable HTTP/2.
799
- target_concurrency: Target concurrency for the server.
799
+ target_concurrency: Target concurrency for the server; 0 disables autoscaling.
800
800
  cloud: Cloud provider (aws, gcp, oci, auto).
801
801
  region: Region(s) to run on.
802
802
  nonpreemptible: Whether to use non-preemptible instances.
@@ -1792,7 +1792,7 @@ class App:
1792
1792
  exit_grace_period: Grace period for in-flight requests on shutdown.
1793
1793
  routing_regions: Regions to deploy proxy endpoints.
1794
1794
  h2_enabled: Enable HTTP/2.
1795
- target_concurrency: Target concurrency for the server.
1795
+ target_concurrency: Target concurrency for the server; 0 disables autoscaling.
1796
1796
  cloud: Cloud provider (aws, gcp, oci, auto).
1797
1797
  region: Region(s) to run on.
1798
1798
  nonpreemptible: Whether to use non-preemptible instances.
@@ -19,6 +19,7 @@ from .container import container_cli
19
19
  from .dashboard import dashboard
20
20
  from .dict import dict_cli
21
21
  from .environment import environment_cli
22
+ from .image import image_cli
22
23
  from .launch import launch_cli
23
24
  from .logo import print_logo
24
25
  from .network_file_system import nfs_cli
@@ -106,6 +107,7 @@ entrypoint_cli.add_command(container_cli, panel="Deployments")
106
107
  # cluster is hidden while multi-node is in beta/experimental
107
108
  entrypoint_cli.add_command(cluster_cli, panel="Deployments", hidden=True)
108
109
 
110
+ entrypoint_cli.add_command(image_cli, panel="Storage")
109
111
  entrypoint_cli.add_command(dict_cli, panel="Storage")
110
112
  entrypoint_cli.add_command(nfs_cli, panel="Storage")
111
113
  entrypoint_cli.add_command(secret_cli, panel="Storage")
@@ -0,0 +1,110 @@
1
+ # Copyright Modal Labs 2026
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+ import json as json_module
7
+ from collections.abc import AsyncIterator
8
+ from typing import Optional
9
+
10
+ import click
11
+
12
+ from modal._environments import ensure_env
13
+ from modal._utils.async_utils import synchronizer
14
+ from modal._utils.time_utils import timestamp_to_localized_str
15
+ from modal.cli.utils import display_table, env_option
16
+ from modal.client import _Client
17
+ from modal.output import OutputManager
18
+ from modal_proto import api_pb2
19
+
20
+ from ._help import ModalGroup
21
+
22
+ IMAGE_REGISTRY_LIST_PAGE_SIZE = 100
23
+ IMAGE_REGISTRY_LIST_PAGE_DELAY_SECONDS = 1.0
24
+
25
+ image_cli = ModalGroup(name="image", help="Manage Images.")
26
+ image_registry_cli = ModalGroup(name="registry", help="Manage the Modal Image name/tag registry.")
27
+ image_cli.add_command(image_registry_cli)
28
+
29
+
30
+ def _print_result_summary(count: int) -> None:
31
+ result_label = "result" if count == 1 else "results"
32
+ OutputManager.get().print(f"Showing {count} {result_label}")
33
+
34
+
35
+ def _tag_item_json(item: api_pb2.ImageListTagsItem) -> dict[str, str]:
36
+ return {
37
+ "tag": item.tag,
38
+ "image_id": item.image_id,
39
+ "created_at": timestamp_to_localized_str(item.created_at, True) or "-",
40
+ "updated_at": timestamp_to_localized_str(item.updated_at, True) or "-",
41
+ }
42
+
43
+
44
+ def _tag_item_row(item: api_pb2.ImageListTagsItem) -> tuple[str, str, str]:
45
+ return (
46
+ item.tag,
47
+ item.image_id,
48
+ timestamp_to_localized_str(item.updated_at, False) or "-",
49
+ )
50
+
51
+
52
+ async def _iter_tag_pages(
53
+ client: _Client, env: str, prefix: str
54
+ ) -> AsyncIterator[tuple[str, list[api_pb2.ImageListTagsItem]]]:
55
+ page_token = ""
56
+ environment_name = env
57
+
58
+ while True:
59
+ response = await client.stub.ImageListTags(
60
+ api_pb2.ImageListTagsRequest(
61
+ environment_name=env,
62
+ tag_prefix=prefix,
63
+ max_objects=IMAGE_REGISTRY_LIST_PAGE_SIZE,
64
+ page_token=page_token,
65
+ )
66
+ )
67
+ environment_name = response.environment_name
68
+ yield environment_name, list(response.items)
69
+
70
+ page_token = response.next_page_token
71
+ if not page_token:
72
+ return
73
+ await asyncio.sleep(IMAGE_REGISTRY_LIST_PAGE_DELAY_SECONDS)
74
+
75
+
76
+ @image_registry_cli.command("list", help="List named Images.")
77
+ @env_option
78
+ @click.option("--prefix", default="", help="Only include named image tags that start with this prefix.")
79
+ @click.option("--json", is_flag=True, default=False)
80
+ @synchronizer.create_blocking
81
+ async def list_(
82
+ env: Optional[str] = None,
83
+ prefix: str = "",
84
+ json: bool = False,
85
+ ):
86
+ env = ensure_env(env)
87
+ client = await _Client.from_env()
88
+
89
+ if json:
90
+ count = 0
91
+ click.echo("[", nl=False)
92
+ async for _, page_items in _iter_tag_pages(client, env, prefix):
93
+ for item in page_items:
94
+ if count:
95
+ click.echo(",", nl=False)
96
+ click.echo(json_module.dumps(_tag_item_json(item)), nl=False)
97
+ count += 1
98
+ click.echo("]")
99
+ return
100
+
101
+ count = 0
102
+ first_page = True
103
+ async for environment_name, page_items in _iter_tag_pages(client, env, prefix):
104
+ if first_page or page_items:
105
+ title = f"Named Images in environment '{environment_name}'" if first_page else ""
106
+ display_table(["Tag", "Image ID", "Updated at"], [_tag_item_row(item) for item in page_items], title=title)
107
+ first_page = False
108
+ count += len(page_items)
109
+
110
+ _print_result_summary(count)
@@ -35,7 +35,7 @@ class _Client:
35
35
  server_url: str,
36
36
  client_type: int,
37
37
  credentials: typing.Optional[tuple[str, str]],
38
- version: str = "1.4.4.dev20",
38
+ version: str = "1.4.4.dev21",
39
39
  ):
40
40
  """mdmd:hidden
41
41
  The Modal client object is not intended to be instantiated directly by users.
@@ -205,7 +205,7 @@ class Client:
205
205
  server_url: str,
206
206
  client_type: int,
207
207
  credentials: typing.Optional[tuple[str, str]],
208
- version: str = "1.4.4.dev20",
208
+ version: str = "1.4.4.dev21",
209
209
  ):
210
210
  """mdmd:hidden
211
211
  The Modal client object is not intended to be instantiated directly by users.
@@ -121,6 +121,30 @@ class Function(
121
121
  """
122
122
  ...
123
123
 
124
+ class ___update_autoscaler_spec(typing_extensions.Protocol):
125
+ def __call__(
126
+ self,
127
+ /,
128
+ *,
129
+ min_containers: typing.Optional[int] = None,
130
+ max_containers: typing.Optional[int] = None,
131
+ buffer_containers: typing.Optional[int] = None,
132
+ scaledown_window: typing.Optional[int] = None,
133
+ target_concurrency: typing.Optional[int] = None,
134
+ ) -> None: ...
135
+ async def aio(
136
+ self,
137
+ /,
138
+ *,
139
+ min_containers: typing.Optional[int] = None,
140
+ max_containers: typing.Optional[int] = None,
141
+ buffer_containers: typing.Optional[int] = None,
142
+ scaledown_window: typing.Optional[int] = None,
143
+ target_concurrency: typing.Optional[int] = None,
144
+ ) -> None: ...
145
+
146
+ _update_autoscaler: ___update_autoscaler_spec
147
+
124
148
  class __update_autoscaler_spec(typing_extensions.Protocol):
125
149
  def __call__(
126
150
  self,
@@ -157,8 +181,7 @@ class Function(
157
181
 
158
182
  # Extend the scaledown window to increase the amount of time that idle containers stay alive
159
183
  f.update_autoscaler(scaledown_window=300)
160
-
161
- ```
184
+ ```
162
185
  """
163
186
  ...
164
187
 
@@ -197,8 +220,7 @@ class Function(
197
220
 
198
221
  # Extend the scaledown window to increase the amount of time that idle containers stay alive
199
222
  f.update_autoscaler(scaledown_window=300)
200
-
201
- ```
223
+ ```
202
224
  """
203
225
  ...
204
226
 
@@ -465,7 +487,7 @@ class Function(
465
487
 
466
488
  _call_generator: ___call_generator_spec
467
489
 
468
- class __remote_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER]):
490
+ class __remote_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER]):
469
491
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> ReturnType_INNER:
470
492
  """Calls the function remotely, executing it with the given arguments and returning the execution's result.
471
493
 
@@ -490,7 +512,7 @@ class Function(
490
512
  """
491
513
  ...
492
514
 
493
- remote: __remote_spec[modal._functions.P, modal._functions.ReturnType]
515
+ remote: __remote_spec[modal._functions.ReturnType, modal._functions.P]
494
516
 
495
517
  class __remote_gen_spec(typing_extensions.Protocol):
496
518
  def __call__(self, /, *args, **kwargs) -> typing.Generator[typing.Any, None, None]:
@@ -540,7 +562,7 @@ class Function(
540
562
  """
541
563
  ...
542
564
 
543
- class ___experimental_spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER]):
565
+ class ___experimental_spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER]):
544
566
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
545
567
  """[Experimental] Calls the function with the given arguments, without waiting for the results.
546
568
 
@@ -573,7 +595,7 @@ class Function(
573
595
  """
574
596
  ...
575
597
 
576
- _experimental_spawn: ___experimental_spawn_spec[modal._functions.P, modal._functions.ReturnType]
598
+ _experimental_spawn: ___experimental_spawn_spec[modal._functions.ReturnType, modal._functions.P]
577
599
 
578
600
  class ___spawn_map_inner_spec(typing_extensions.Protocol[P_INNER]):
579
601
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> None: ...
@@ -581,7 +603,7 @@ class Function(
581
603
 
582
604
  _spawn_map_inner: ___spawn_map_inner_spec[modal._functions.P]
583
605
 
584
- class __spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER]):
606
+ class __spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER]):
585
607
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
586
608
  """Calls the function with the given arguments, without waiting for the results.
587
609
 
@@ -614,7 +636,7 @@ class Function(
614
636
  """
615
637
  ...
616
638
 
617
- spawn: __spawn_spec[modal._functions.P, modal._functions.ReturnType]
639
+ spawn: __spawn_spec[modal._functions.ReturnType, modal._functions.P]
618
640
 
619
641
  def get_raw_f(self) -> collections.abc.Callable[..., typing.Any]:
620
642
  """Return the inner Python object wrapped by this Modal Function.
@@ -51,6 +51,7 @@ class Server:
51
51
  max_containers: typing.Optional[int] = None,
52
52
  buffer_containers: typing.Optional[int] = None,
53
53
  scaledown_window: typing.Optional[int] = None,
54
+ target_concurrency: typing.Optional[int] = None,
54
55
  ) -> None:
55
56
  """Override the current autoscaler behavior for this Server.
56
57
 
@@ -65,7 +66,13 @@ class Server:
65
66
 
66
67
  # Limit this Server to avoid spinning up more than 5 containers
67
68
  server.update_autoscaler(max_containers=5)
68
- ```
69
+
70
+ # Adjust Server autoscaling to target 20 concurrent requests per replica
71
+ server.update_autoscaler(target_concurrency=20)
72
+
73
+ # Disable the Server autoscaling by setting target_concurrency to 0
74
+ server.update_autoscaler(target_concurrency=0)
75
+ ```
69
76
  """
70
77
  ...
71
78
 
@@ -77,6 +84,7 @@ class Server:
77
84
  max_containers: typing.Optional[int] = None,
78
85
  buffer_containers: typing.Optional[int] = None,
79
86
  scaledown_window: typing.Optional[int] = None,
87
+ target_concurrency: typing.Optional[int] = None,
80
88
  ) -> None:
81
89
  """Override the current autoscaler behavior for this Server.
82
90
 
@@ -91,7 +99,13 @@ class Server:
91
99
 
92
100
  # Limit this Server to avoid spinning up more than 5 containers
93
101
  server.update_autoscaler(max_containers=5)
94
- ```
102
+
103
+ # Adjust Server autoscaling to target 20 concurrent requests per replica
104
+ server.update_autoscaler(target_concurrency=20)
105
+
106
+ # Disable the Server autoscaling by setting target_concurrency to 0
107
+ server.update_autoscaler(target_concurrency=0)
108
+ ```
95
109
  """
96
110
  ...
97
111
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.4.4.dev20
3
+ Version: 1.4.4.dev21
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License-Expression: Apache-2.0
@@ -173,6 +173,7 @@ modal/cli/dashboard.py
173
173
  modal/cli/dict.py
174
174
  modal/cli/entry_point.py
175
175
  modal/cli/environment.py
176
+ modal/cli/image.py
176
177
  modal/cli/import_refs.py
177
178
  modal/cli/launch.py
178
179
  modal/cli/logo.py
@@ -1,5 +1,6 @@
1
1
  # Copyright Modal Labs 2023
2
2
  import inspect
3
+ import re
3
4
  import sys
4
5
  from pathlib import Path
5
6
  from typing import cast
@@ -9,6 +10,11 @@ from click import Command, Context, Group
9
10
  from modal.cli.entry_point import entrypoint_cli
10
11
 
11
12
 
13
+ def _escape_svelte(text: str) -> str:
14
+ """Wrap {placeholder} patterns in backticks so mdsvex/Svelte won't interpret them as expressions."""
15
+ return re.sub(r"(?<!`)\{([a-z_]+)\}(?!`)", r"`{\1}`", text)
16
+
17
+
12
18
  # Adapted from typer_cli for generating CLI docs from click commands
13
19
  # (see https://github.com/tiangolo/typer-cli/issues/50)
14
20
  def get_docs_for_click(
@@ -26,7 +32,7 @@ def get_docs_for_click(
26
32
  title = f"`{command_name}`" if command_name else "CLI"
27
33
  docs += f" {title}\n\n"
28
34
  if obj.help:
29
- docs += f"{inspect.cleandoc(obj.help)}\n\n"
35
+ docs += f"{_escape_svelte(inspect.cleandoc(obj.help))}\n\n"
30
36
  usage_pieces = obj.collect_usage_pieces(ctx)
31
37
  if usage_pieces:
32
38
  docs += "**Usage**:\n\n"
@@ -51,7 +57,7 @@ def get_docs_for_click(
51
57
  for arg_name, arg_help in args:
52
58
  docs += f"* `{arg_name}`"
53
59
  if arg_help:
54
- docs += f": {arg_help}"
60
+ docs += f": {_escape_svelte(arg_help)}"
55
61
  docs += "\n"
56
62
  docs += "\n"
57
63
  if opts:
@@ -59,11 +65,11 @@ def get_docs_for_click(
59
65
  for opt_name, opt_help in opts:
60
66
  docs += f"* `{opt_name}`"
61
67
  if opt_help:
62
- docs += f": {opt_help}"
68
+ docs += f": {_escape_svelte(opt_help)}"
63
69
  docs += "\n"
64
70
  docs += "\n"
65
71
  if obj.epilog:
66
- docs += f"{obj.epilog}\n\n"
72
+ docs += f"{_escape_svelte(obj.epilog)}\n\n"
67
73
  if isinstance(obj, Group):
68
74
  group: Group = cast(Group, obj)
69
75
  commands = group.list_commands(ctx)
@@ -77,7 +83,7 @@ def get_docs_for_click(
77
83
  docs += f"* `{command_obj.name}`"
78
84
  command_help = command_obj.get_short_help_str(limit=250)
79
85
  if command_help:
80
- docs += f": {command_help}"
86
+ docs += f": {_escape_svelte(command_help)}"
81
87
  docs += "\n"
82
88
  docs += "\n"
83
89
  for command in commands:
@@ -435,10 +435,18 @@ class ModalClientBase(abc.ABC):
435
435
  async def ImageJoinStreaming(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.ImageJoinStreamingRequest, modal_proto.api_pb2.ImageJoinStreamingResponse]') -> None:
436
436
  pass
437
437
 
438
+ @abc.abstractmethod
439
+ async def ImageListTags(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.ImageListTagsRequest, modal_proto.api_pb2.ImageListTagsResponse]') -> None:
440
+ pass
441
+
438
442
  @abc.abstractmethod
439
443
  async def ImagePublish(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.ImagePublishRequest, modal_proto.api_pb2.ImagePublishResponse]') -> None:
440
444
  pass
441
445
 
446
+ @abc.abstractmethod
447
+ async def ImageTagRevisions(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.ImageTagRevisionsRequest, modal_proto.api_pb2.ImageTagRevisionsResponse]') -> None:
448
+ pass
449
+
442
450
  @abc.abstractmethod
443
451
  async def MapAwait(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.MapAwaitRequest, modal_proto.api_pb2.MapAwaitResponse]') -> None:
444
452
  pass
@@ -1461,12 +1469,24 @@ class ModalClientBase(abc.ABC):
1461
1469
  modal_proto.api_pb2.ImageJoinStreamingRequest,
1462
1470
  modal_proto.api_pb2.ImageJoinStreamingResponse,
1463
1471
  ),
1472
+ '/modal.client.ModalClient/ImageListTags': grpclib.const.Handler(
1473
+ self.ImageListTags,
1474
+ grpclib.const.Cardinality.UNARY_UNARY,
1475
+ modal_proto.api_pb2.ImageListTagsRequest,
1476
+ modal_proto.api_pb2.ImageListTagsResponse,
1477
+ ),
1464
1478
  '/modal.client.ModalClient/ImagePublish': grpclib.const.Handler(
1465
1479
  self.ImagePublish,
1466
1480
  grpclib.const.Cardinality.UNARY_UNARY,
1467
1481
  modal_proto.api_pb2.ImagePublishRequest,
1468
1482
  modal_proto.api_pb2.ImagePublishResponse,
1469
1483
  ),
1484
+ '/modal.client.ModalClient/ImageTagRevisions': grpclib.const.Handler(
1485
+ self.ImageTagRevisions,
1486
+ grpclib.const.Cardinality.UNARY_UNARY,
1487
+ modal_proto.api_pb2.ImageTagRevisionsRequest,
1488
+ modal_proto.api_pb2.ImageTagRevisionsResponse,
1489
+ ),
1470
1490
  '/modal.client.ModalClient/MapAwait': grpclib.const.Handler(
1471
1491
  self.MapAwait,
1472
1492
  grpclib.const.Cardinality.UNARY_UNARY,
@@ -2691,12 +2711,24 @@ class ModalClientStub:
2691
2711
  modal_proto.api_pb2.ImageJoinStreamingRequest,
2692
2712
  modal_proto.api_pb2.ImageJoinStreamingResponse,
2693
2713
  )
2714
+ self.ImageListTags = grpclib.client.UnaryUnaryMethod(
2715
+ channel,
2716
+ '/modal.client.ModalClient/ImageListTags',
2717
+ modal_proto.api_pb2.ImageListTagsRequest,
2718
+ modal_proto.api_pb2.ImageListTagsResponse,
2719
+ )
2694
2720
  self.ImagePublish = grpclib.client.UnaryUnaryMethod(
2695
2721
  channel,
2696
2722
  '/modal.client.ModalClient/ImagePublish',
2697
2723
  modal_proto.api_pb2.ImagePublishRequest,
2698
2724
  modal_proto.api_pb2.ImagePublishResponse,
2699
2725
  )
2726
+ self.ImageTagRevisions = grpclib.client.UnaryUnaryMethod(
2727
+ channel,
2728
+ '/modal.client.ModalClient/ImageTagRevisions',
2729
+ modal_proto.api_pb2.ImageTagRevisionsRequest,
2730
+ modal_proto.api_pb2.ImageTagRevisionsResponse,
2731
+ )
2700
2732
  self.MapAwait = grpclib.client.UnaryUnaryMethod(
2701
2733
  channel,
2702
2734
  '/modal.client.ModalClient/MapAwait',