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.
Files changed (236) hide show
  1. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/PKG-INFO +1 -1
  2. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_environments.py +6 -2
  3. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_functions.py +29 -7
  4. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_image.py +50 -41
  5. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_server.py +7 -2
  6. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/environment.py +4 -3
  7. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/image.py +13 -25
  8. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/client.pyi +2 -2
  9. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cls.py +7 -1
  10. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cls.pyi +16 -3
  11. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/environments.pyi +14 -2
  12. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/functions.pyi +41 -11
  13. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/image.pyi +6 -4
  14. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/server.pyi +11 -2
  15. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/types.py +38 -0
  16. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal.egg-info/PKG-INFO +1 -1
  17. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal_proto/api_pb2.py +702 -702
  18. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal_proto/api_pb2.pyi +16 -3
  19. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal_version/__init__.py +1 -1
  20. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/LICENSE +0 -0
  21. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/README.md +0 -0
  22. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/__init__.py +0 -0
  23. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/__main__.py +0 -0
  24. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_billing.py +0 -0
  25. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_clustered_functions.py +0 -0
  26. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_clustered_functions.pyi +0 -0
  27. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_container_entrypoint.py +0 -0
  28. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_function_variants.py +0 -0
  29. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_grpc_client.py +0 -0
  30. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_ipython.py +0 -0
  31. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_load_context.py +0 -0
  32. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_location.py +0 -0
  33. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_logs.py +0 -0
  34. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_logs_manager.py +0 -0
  35. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_logs_manager.pyi +0 -0
  36. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_object.py +0 -0
  37. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_output/__init__.py +0 -0
  38. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_output/manager.py +0 -0
  39. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_output/pty.py +0 -0
  40. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_output/rich.py +0 -0
  41. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_output/status.py +0 -0
  42. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_partial_function.py +0 -0
  43. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_resolver.py +0 -0
  44. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_resources.py +0 -0
  45. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_runtime/__init__.py +0 -0
  46. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_runtime/asgi.py +0 -0
  47. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_runtime/container_io_manager.py +0 -0
  48. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_runtime/container_io_manager.pyi +0 -0
  49. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_runtime/execution_context.py +0 -0
  50. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_runtime/execution_context.pyi +0 -0
  51. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_runtime/gpu_memory_snapshot.py +0 -0
  52. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_runtime/task_lifecycle_manager.py +0 -0
  53. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_runtime/task_lifecycle_manager.pyi +0 -0
  54. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_runtime/telemetry.py +0 -0
  55. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_runtime/user_code_event_loop.py +0 -0
  56. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_runtime/user_code_imports.py +0 -0
  57. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_serialization.py +0 -0
  58. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_supports_logs.py +0 -0
  59. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_traceback.py +0 -0
  60. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_tunnel.py +0 -0
  61. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_tunnel.pyi +0 -0
  62. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_type_manager.py +0 -0
  63. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/__init__.py +0 -0
  64. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/app_utils.py +0 -0
  65. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/async_utils.py +0 -0
  66. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/auth_token_manager.py +0 -0
  67. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/blob_utils.py +0 -0
  68. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/browser_utils.py +0 -0
  69. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/bytes_io_segment_payload.py +0 -0
  70. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/curl_utils.py +0 -0
  71. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/deprecation.py +0 -0
  72. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/display_utils.py +0 -0
  73. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/docker_utils.py +0 -0
  74. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/function_utils.py +0 -0
  75. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/git_utils.py +0 -0
  76. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/grpc_testing.py +0 -0
  77. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/grpc_utils.py +0 -0
  78. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/hash_utils.py +0 -0
  79. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/http_utils.py +0 -0
  80. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/jwt_utils.py +0 -0
  81. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/logger.py +0 -0
  82. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/mount_utils.py +0 -0
  83. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/name_utils.py +0 -0
  84. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/package_utils.py +0 -0
  85. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/pattern_utils.py +0 -0
  86. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/proxy_support.py +0 -0
  87. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/rand_pb_testing.py +0 -0
  88. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/sandbox_fs_utils.py +0 -0
  89. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/shell_utils.py +0 -0
  90. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/task_command_router_client.py +0 -0
  91. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_utils/time_utils.py +0 -0
  92. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_vendor/__init__.py +0 -0
  93. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_vendor/a2wsgi_wsgi.py +0 -0
  94. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_vendor/cloudpickle.py +0 -0
  95. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_vendor/tblib.py +0 -0
  96. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_vendor/version.py +0 -0
  97. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_watcher.py +0 -0
  98. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/_workspace.py +0 -0
  99. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/app.py +0 -0
  100. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/app.pyi +0 -0
  101. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/billing.py +0 -0
  102. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/billing.pyi +0 -0
  103. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/builder/2023.12.312.txt +0 -0
  104. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/builder/2023.12.txt +0 -0
  105. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/builder/2024.04.txt +0 -0
  106. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/builder/2024.10.txt +0 -0
  107. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/builder/2025.06.txt +0 -0
  108. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/builder/PREVIEW.txt +0 -0
  109. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/builder/README.md +0 -0
  110. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/builder/base-images.json +0 -0
  111. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/call_graph.py +0 -0
  112. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/__init__.py +0 -0
  113. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/_download.py +0 -0
  114. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/_help.py +0 -0
  115. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/_traceback.py +0 -0
  116. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/app.py +0 -0
  117. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/billing.py +0 -0
  118. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/bootstrap.py +0 -0
  119. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/changelog.py +0 -0
  120. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/cluster.py +0 -0
  121. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/config.py +0 -0
  122. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/container.py +0 -0
  123. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/curl.py +0 -0
  124. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/dashboard.py +0 -0
  125. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/dict.py +0 -0
  126. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/endpoint.py +0 -0
  127. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/entry_point.py +0 -0
  128. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/import_refs.py +0 -0
  129. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/launch.py +0 -0
  130. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/logo.py +0 -0
  131. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/network_file_system.py +0 -0
  132. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/profile.py +0 -0
  133. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/programs/__init__.py +0 -0
  134. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/programs/run_jupyter.py +0 -0
  135. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/programs/vscode.py +0 -0
  136. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/queues.py +0 -0
  137. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/run.py +0 -0
  138. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/secret.py +0 -0
  139. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/selector.py +0 -0
  140. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/shell.py +0 -0
  141. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/skills.py +0 -0
  142. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/token.py +0 -0
  143. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/utils.py +0 -0
  144. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/volume.py +0 -0
  145. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cli/workspace.py +0 -0
  146. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/client.py +0 -0
  147. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cloud_bucket_mount.py +0 -0
  148. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/cloud_bucket_mount.pyi +0 -0
  149. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/config.py +0 -0
  150. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/container_process.py +0 -0
  151. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/container_process.pyi +0 -0
  152. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/dict.py +0 -0
  153. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/dict.pyi +0 -0
  154. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/environments.py +0 -0
  155. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/exception.py +0 -0
  156. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/experimental/__init__.py +0 -0
  157. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/experimental/flash.py +0 -0
  158. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/experimental/flash.pyi +0 -0
  159. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/experimental/ipython.py +0 -0
  160. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/file_io.py +0 -0
  161. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/file_io.pyi +0 -0
  162. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/file_pattern_matcher.py +0 -0
  163. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/functions.py +0 -0
  164. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/image.py +0 -0
  165. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/io_streams.py +0 -0
  166. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/io_streams.pyi +0 -0
  167. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/mount.py +0 -0
  168. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/mount.pyi +0 -0
  169. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/network_file_system.py +0 -0
  170. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/network_file_system.pyi +0 -0
  171. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/object.py +0 -0
  172. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/object.pyi +0 -0
  173. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/output.py +0 -0
  174. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/parallel_map.py +0 -0
  175. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/parallel_map.pyi +0 -0
  176. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/partial_function.py +0 -0
  177. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/partial_function.pyi +0 -0
  178. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/proxy.py +0 -0
  179. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/proxy.pyi +0 -0
  180. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/py.typed +0 -0
  181. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/queue.py +0 -0
  182. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/queue.pyi +0 -0
  183. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/retries.py +0 -0
  184. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/runner.py +0 -0
  185. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/runner.pyi +0 -0
  186. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/running_app.py +0 -0
  187. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/sandbox.py +0 -0
  188. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/sandbox.pyi +0 -0
  189. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/sandbox_fs.py +0 -0
  190. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/sandbox_fs.pyi +0 -0
  191. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/schedule.py +0 -0
  192. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/scheduler_placement.py +0 -0
  193. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/secret.py +0 -0
  194. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/secret.pyi +0 -0
  195. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/server.py +0 -0
  196. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/serving.py +0 -0
  197. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/serving.pyi +0 -0
  198. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/skills/modal/SKILL.md +0 -0
  199. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/snapshot.py +0 -0
  200. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/snapshot.pyi +0 -0
  201. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/stream_type.py +0 -0
  202. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/token_flow.py +0 -0
  203. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/token_flow.pyi +0 -0
  204. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/volume.py +0 -0
  205. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/volume.pyi +0 -0
  206. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/workspace.py +0 -0
  207. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal/workspace.pyi +0 -0
  208. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal.egg-info/SOURCES.txt +0 -0
  209. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal.egg-info/dependency_links.txt +0 -0
  210. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal.egg-info/entry_points.txt +0 -0
  211. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal.egg-info/requires.txt +0 -0
  212. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal.egg-info/top_level.txt +0 -0
  213. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal_docs/__init__.py +0 -0
  214. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal_docs/gen_cli_docs.py +0 -0
  215. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal_docs/gen_cli_docs_main.py +0 -0
  216. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal_docs/gen_reference_docs.py +0 -0
  217. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal_docs/gen_reference_docs_main.py +0 -0
  218. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal_docs/mdmd/__init__.py +0 -0
  219. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal_docs/mdmd/mdmd.py +0 -0
  220. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal_docs/mdmd/signatures.py +0 -0
  221. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal_docs/mdmd/types.py +0 -0
  222. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal_docs/reference_intro.md +0 -0
  223. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal_proto/__init__.py +0 -0
  224. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal_proto/api_grpc.py +0 -0
  225. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal_proto/api_pb2_grpc.py +0 -0
  226. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal_proto/api_pb2_grpc.pyi +0 -0
  227. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal_proto/modal_api_grpc.py +0 -0
  228. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal_proto/py.typed +0 -0
  229. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal_proto/task_command_router_grpc.py +0 -0
  230. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal_proto/task_command_router_pb2.py +0 -0
  231. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal_proto/task_command_router_pb2.pyi +0 -0
  232. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal_proto/task_command_router_pb2_grpc.py +0 -0
  233. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal_proto/task_command_router_pb2_grpc.pyi +0 -0
  234. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/modal_version/__main__.py +0 -0
  235. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/pyproject.toml +0 -0
  236. {modal-1.5.4.dev0 → modal-1.5.4.dev2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.5.4.dev0
3
+ Version: 1.5.4.dev2
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License-Expression: Apache-2.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
- await client.stub.EnvironmentCreate(api_pb2.EnvironmentCreateRequest(name=name, is_managed=restricted))
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
- ) -> None:
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
- # One idea would be for FunctionUpdateScheduleParams to return the current (coalesced) settings
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
- ) -> None:
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 _parse_named_image_ref(name: str) -> tuple[str, str]:
121
- """Parse an image reference, returning (namespace_prefix, name_tag).
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
- prefix = ""
136
- if "/" in image_name:
137
- prefix, image_name = image_name.rsplit("/", 1)
138
- if not prefix:
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
- full_name = f"{prefix}/{image_name}" if prefix else image_name
147
- return prefix, f"{full_name}:{tag}"
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 - if no tag part is included `":latest"` is used,
2936
- matching Docker conventions.
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
- namespace_prefix, tag = _parse_named_image_ref(name)
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=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(tag, environment_name)
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 (using the `name:tag`). If no tag is included in the name,
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
- environment_name=resolved_env,
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
- ) -> None:
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()._update_autoscaler(
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
- def create(name: str, restricted: bool = False):
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 _parse_named_image_ref
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.exception import InvalidError
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
- env: str,
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=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, env: str, tag: str, first_page: api_pb2.ImageTagRevisionsResponse
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, env, tag, response.next_page_token)
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
- explicit_env = env # None when --env is not passed by the user
172
- env = ensure_env(env)
173
- try:
174
- namespace_prefix, name_tag = _parse_named_image_ref(name)
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, env, name_tag, "")
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, env, name_tag, first_page):
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, env, name_tag, first_page):
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.dev0",
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.dev0",
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
- ) -> None:
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
- ) -> None:
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
- ) -> None:
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
- ) -> None:
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, /, name: str, *, restricted: bool = False, client: typing.Optional[modal.client.Client] = None
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, /, name: str, *, restricted: bool = False, client: typing.Optional[modal.client.Client] = None
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