modAL 1.5.1__tar.gz → 1.5.1.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.
Files changed (234) hide show
  1. {modal-1.5.1 → modal-1.5.1.dev0}/PKG-INFO +3 -6
  2. {modal-1.5.1 → modal-1.5.1.dev0}/README.md +1 -1
  3. {modal-1.5.1 → modal-1.5.1.dev0}/modal/__init__.py +0 -2
  4. modal-1.5.1.dev0/modal/_billing.py +94 -0
  5. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_environments.py +1 -84
  6. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_functions.py +9 -13
  7. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_grpc_client.py +3 -3
  8. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_image.py +4 -39
  9. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_partial_function.py +1 -1
  10. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_runtime/gpu_memory_snapshot.py +0 -5
  11. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_runtime/task_lifecycle_manager.py +4 -9
  12. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_server.py +18 -55
  13. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_utils/blob_utils.py +1 -3
  14. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_utils/grpc_utils.py +8 -85
  15. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_utils/http_utils.py +1 -20
  16. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_utils/task_command_router_client.py +2 -29
  17. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_utils/time_utils.py +0 -23
  18. modal-1.5.1.dev0/modal/_workspace.py +116 -0
  19. {modal-1.5.1 → modal-1.5.1.dev0}/modal/app.py +23 -37
  20. {modal-1.5.1 → modal-1.5.1.dev0}/modal/app.pyi +42 -56
  21. {modal-1.5.1 → modal-1.5.1.dev0}/modal/billing.py +2 -3
  22. {modal-1.5.1 → modal-1.5.1.dev0}/modal/cli/_help.py +3 -3
  23. {modal-1.5.1 → modal-1.5.1.dev0}/modal/cli/app.py +3 -24
  24. {modal-1.5.1 → modal-1.5.1.dev0}/modal/cli/billing.py +77 -108
  25. {modal-1.5.1 → modal-1.5.1.dev0}/modal/cli/changelog.py +1 -1
  26. {modal-1.5.1 → modal-1.5.1.dev0}/modal/cli/config.py +1 -1
  27. {modal-1.5.1 → modal-1.5.1.dev0}/modal/cli/entry_point.py +2 -8
  28. {modal-1.5.1 → modal-1.5.1.dev0}/modal/cli/environment.py +1 -140
  29. {modal-1.5.1 → modal-1.5.1.dev0}/modal/cli/shell.py +14 -7
  30. {modal-1.5.1 → modal-1.5.1.dev0}/modal/cli/utils.py +3 -8
  31. {modal-1.5.1 → modal-1.5.1.dev0}/modal/client.py +1 -1
  32. {modal-1.5.1 → modal-1.5.1.dev0}/modal/client.pyi +10 -2
  33. {modal-1.5.1 → modal-1.5.1.dev0}/modal/cls.py +2 -2
  34. {modal-1.5.1 → modal-1.5.1.dev0}/modal/cls.pyi +4 -4
  35. {modal-1.5.1 → modal-1.5.1.dev0}/modal/config.py +0 -1
  36. {modal-1.5.1 → modal-1.5.1.dev0}/modal/environments.py +0 -2
  37. {modal-1.5.1 → modal-1.5.1.dev0}/modal/environments.pyi +1 -91
  38. {modal-1.5.1 → modal-1.5.1.dev0}/modal/exception.py +1 -1
  39. {modal-1.5.1 → modal-1.5.1.dev0}/modal/functions.pyi +18 -21
  40. {modal-1.5.1 → modal-1.5.1.dev0}/modal/partial_function.pyi +1 -1
  41. {modal-1.5.1 → modal-1.5.1.dev0}/modal/runner.py +12 -16
  42. {modal-1.5.1 → modal-1.5.1.dev0}/modal/sandbox.py +53 -120
  43. {modal-1.5.1 → modal-1.5.1.dev0}/modal/sandbox.pyi +38 -110
  44. {modal-1.5.1 → modal-1.5.1.dev0}/modal/sandbox_fs.py +2 -39
  45. {modal-1.5.1 → modal-1.5.1.dev0}/modal/schedule.py +1 -1
  46. {modal-1.5.1 → modal-1.5.1.dev0}/modal/secret.py +9 -39
  47. {modal-1.5.1 → modal-1.5.1.dev0}/modal/secret.pyi +0 -19
  48. {modal-1.5.1 → modal-1.5.1.dev0}/modal/server.pyi +15 -78
  49. modal-1.5.1.dev0/modal/workspace.py +12 -0
  50. modal-1.5.1.dev0/modal/workspace.pyi +105 -0
  51. {modal-1.5.1 → modal-1.5.1.dev0}/modal.egg-info/PKG-INFO +3 -6
  52. {modal-1.5.1 → modal-1.5.1.dev0}/modal.egg-info/SOURCES.txt +0 -6
  53. {modal-1.5.1 → modal-1.5.1.dev0}/modal.egg-info/requires.txt +1 -5
  54. {modal-1.5.1 → modal-1.5.1.dev0}/modal_docs/gen_cli_docs.py +2 -48
  55. {modal-1.5.1 → modal-1.5.1.dev0}/modal_docs/mdmd/mdmd.py +1 -10
  56. {modal-1.5.1 → modal-1.5.1.dev0}/modal_docs/mdmd/types.py +0 -1
  57. {modal-1.5.1 → modal-1.5.1.dev0}/modal_proto/api_grpc.py +3 -195
  58. {modal-1.5.1 → modal-1.5.1.dev0}/modal_proto/api_pb2.py +1095 -1340
  59. {modal-1.5.1 → modal-1.5.1.dev0}/modal_proto/api_pb2.pyi +20 -501
  60. {modal-1.5.1 → modal-1.5.1.dev0}/modal_proto/api_pb2_grpc.py +3 -401
  61. {modal-1.5.1 → modal-1.5.1.dev0}/modal_proto/api_pb2_grpc.pyi +2 -126
  62. {modal-1.5.1 → modal-1.5.1.dev0}/modal_proto/modal_api_grpc.py +0 -12
  63. {modal-1.5.1 → modal-1.5.1.dev0}/modal_proto/task_command_router_grpc.py +0 -32
  64. {modal-1.5.1 → modal-1.5.1.dev0}/modal_proto/task_command_router_pb2.py +79 -119
  65. {modal-1.5.1 → modal-1.5.1.dev0}/modal_proto/task_command_router_pb2.pyi +1 -68
  66. {modal-1.5.1 → modal-1.5.1.dev0}/modal_proto/task_command_router_pb2_grpc.py +2 -71
  67. {modal-1.5.1 → modal-1.5.1.dev0}/modal_proto/task_command_router_pb2_grpc.pyi +4 -30
  68. {modal-1.5.1 → modal-1.5.1.dev0}/modal_version/__init__.py +1 -1
  69. {modal-1.5.1 → modal-1.5.1.dev0}/pyproject.toml +16 -30
  70. modal-1.5.1/modal/_billing.py +0 -134
  71. modal-1.5.1/modal/_utils/curl_utils.py +0 -115
  72. modal-1.5.1/modal/_utils/proxy_support.py +0 -102
  73. modal-1.5.1/modal/_workspace.py +0 -342
  74. modal-1.5.1/modal/billing.pyi +0 -176
  75. modal-1.5.1/modal/cli/curl.py +0 -137
  76. modal-1.5.1/modal/cli/endpoint.py +0 -352
  77. modal-1.5.1/modal/cli/workspace.py +0 -129
  78. modal-1.5.1/modal/workspace.py +0 -25
  79. modal-1.5.1/modal/workspace.pyi +0 -450
  80. {modal-1.5.1 → modal-1.5.1.dev0}/LICENSE +0 -0
  81. {modal-1.5.1 → modal-1.5.1.dev0}/modal/__main__.py +0 -0
  82. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_clustered_functions.py +0 -0
  83. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_clustered_functions.pyi +0 -0
  84. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_container_entrypoint.py +0 -0
  85. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_function_variants.py +0 -0
  86. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_ipython.py +0 -0
  87. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_load_context.py +0 -0
  88. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_location.py +0 -0
  89. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_logs.py +0 -0
  90. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_object.py +0 -0
  91. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_output/__init__.py +0 -0
  92. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_output/manager.py +0 -0
  93. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_output/pty.py +0 -0
  94. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_output/rich.py +0 -0
  95. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_output/status.py +0 -0
  96. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_resolver.py +0 -0
  97. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_resources.py +0 -0
  98. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_runtime/__init__.py +0 -0
  99. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_runtime/asgi.py +0 -0
  100. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_runtime/container_io_manager.py +0 -0
  101. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_runtime/container_io_manager.pyi +0 -0
  102. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_runtime/execution_context.py +0 -0
  103. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_runtime/execution_context.pyi +0 -0
  104. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_runtime/task_lifecycle_manager.pyi +0 -0
  105. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_runtime/telemetry.py +0 -0
  106. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_runtime/user_code_event_loop.py +0 -0
  107. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_runtime/user_code_imports.py +0 -0
  108. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_serialization.py +0 -0
  109. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_traceback.py +0 -0
  110. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_tunnel.py +0 -0
  111. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_tunnel.pyi +0 -0
  112. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_type_manager.py +0 -0
  113. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_utils/__init__.py +0 -0
  114. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_utils/app_utils.py +0 -0
  115. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_utils/async_utils.py +0 -0
  116. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_utils/auth_token_manager.py +0 -0
  117. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_utils/browser_utils.py +0 -0
  118. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_utils/bytes_io_segment_payload.py +0 -0
  119. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_utils/deprecation.py +0 -0
  120. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_utils/docker_utils.py +0 -0
  121. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_utils/function_utils.py +0 -0
  122. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_utils/git_utils.py +0 -0
  123. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_utils/grpc_testing.py +0 -0
  124. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_utils/hash_utils.py +0 -0
  125. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_utils/jwt_utils.py +0 -0
  126. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_utils/logger.py +0 -0
  127. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_utils/mount_utils.py +0 -0
  128. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_utils/name_utils.py +0 -0
  129. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_utils/package_utils.py +0 -0
  130. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_utils/pattern_utils.py +0 -0
  131. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_utils/rand_pb_testing.py +0 -0
  132. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_utils/sandbox_fs_utils.py +0 -0
  133. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_utils/shell_utils.py +0 -0
  134. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_vendor/__init__.py +0 -0
  135. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_vendor/a2wsgi_wsgi.py +0 -0
  136. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_vendor/cloudpickle.py +0 -0
  137. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_vendor/tblib.py +0 -0
  138. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_vendor/version.py +0 -0
  139. {modal-1.5.1 → modal-1.5.1.dev0}/modal/_watcher.py +0 -0
  140. {modal-1.5.1 → modal-1.5.1.dev0}/modal/builder/2023.12.312.txt +0 -0
  141. {modal-1.5.1 → modal-1.5.1.dev0}/modal/builder/2023.12.txt +0 -0
  142. {modal-1.5.1 → modal-1.5.1.dev0}/modal/builder/2024.04.txt +0 -0
  143. {modal-1.5.1 → modal-1.5.1.dev0}/modal/builder/2024.10.txt +0 -0
  144. {modal-1.5.1 → modal-1.5.1.dev0}/modal/builder/2025.06.txt +0 -0
  145. {modal-1.5.1 → modal-1.5.1.dev0}/modal/builder/PREVIEW.txt +0 -0
  146. {modal-1.5.1 → modal-1.5.1.dev0}/modal/builder/README.md +0 -0
  147. {modal-1.5.1 → modal-1.5.1.dev0}/modal/builder/base-images.json +0 -0
  148. {modal-1.5.1 → modal-1.5.1.dev0}/modal/call_graph.py +0 -0
  149. {modal-1.5.1 → modal-1.5.1.dev0}/modal/cli/__init__.py +0 -0
  150. {modal-1.5.1 → modal-1.5.1.dev0}/modal/cli/_download.py +0 -0
  151. {modal-1.5.1 → modal-1.5.1.dev0}/modal/cli/_traceback.py +0 -0
  152. {modal-1.5.1 → modal-1.5.1.dev0}/modal/cli/bootstrap.py +0 -0
  153. {modal-1.5.1 → modal-1.5.1.dev0}/modal/cli/cluster.py +0 -0
  154. {modal-1.5.1 → modal-1.5.1.dev0}/modal/cli/container.py +0 -0
  155. {modal-1.5.1 → modal-1.5.1.dev0}/modal/cli/dashboard.py +0 -0
  156. {modal-1.5.1 → modal-1.5.1.dev0}/modal/cli/dict.py +0 -0
  157. {modal-1.5.1 → modal-1.5.1.dev0}/modal/cli/image.py +0 -0
  158. {modal-1.5.1 → modal-1.5.1.dev0}/modal/cli/import_refs.py +0 -0
  159. {modal-1.5.1 → modal-1.5.1.dev0}/modal/cli/launch.py +0 -0
  160. {modal-1.5.1 → modal-1.5.1.dev0}/modal/cli/logo.py +0 -0
  161. {modal-1.5.1 → modal-1.5.1.dev0}/modal/cli/network_file_system.py +0 -0
  162. {modal-1.5.1 → modal-1.5.1.dev0}/modal/cli/profile.py +0 -0
  163. {modal-1.5.1 → modal-1.5.1.dev0}/modal/cli/programs/__init__.py +0 -0
  164. {modal-1.5.1 → modal-1.5.1.dev0}/modal/cli/programs/run_jupyter.py +0 -0
  165. {modal-1.5.1 → modal-1.5.1.dev0}/modal/cli/programs/vscode.py +0 -0
  166. {modal-1.5.1 → modal-1.5.1.dev0}/modal/cli/queues.py +0 -0
  167. {modal-1.5.1 → modal-1.5.1.dev0}/modal/cli/run.py +0 -0
  168. {modal-1.5.1 → modal-1.5.1.dev0}/modal/cli/secret.py +0 -0
  169. {modal-1.5.1 → modal-1.5.1.dev0}/modal/cli/selector.py +0 -0
  170. {modal-1.5.1 → modal-1.5.1.dev0}/modal/cli/skills.py +0 -0
  171. {modal-1.5.1 → modal-1.5.1.dev0}/modal/cli/token.py +0 -0
  172. {modal-1.5.1 → modal-1.5.1.dev0}/modal/cli/volume.py +0 -0
  173. {modal-1.5.1 → modal-1.5.1.dev0}/modal/cloud_bucket_mount.py +0 -0
  174. {modal-1.5.1 → modal-1.5.1.dev0}/modal/cloud_bucket_mount.pyi +0 -0
  175. {modal-1.5.1 → modal-1.5.1.dev0}/modal/container_process.py +0 -0
  176. {modal-1.5.1 → modal-1.5.1.dev0}/modal/container_process.pyi +0 -0
  177. {modal-1.5.1 → modal-1.5.1.dev0}/modal/dict.py +0 -0
  178. {modal-1.5.1 → modal-1.5.1.dev0}/modal/dict.pyi +0 -0
  179. {modal-1.5.1 → modal-1.5.1.dev0}/modal/experimental/__init__.py +0 -0
  180. {modal-1.5.1 → modal-1.5.1.dev0}/modal/experimental/flash.py +0 -0
  181. {modal-1.5.1 → modal-1.5.1.dev0}/modal/experimental/flash.pyi +0 -0
  182. {modal-1.5.1 → modal-1.5.1.dev0}/modal/experimental/ipython.py +0 -0
  183. {modal-1.5.1 → modal-1.5.1.dev0}/modal/file_io.py +0 -0
  184. {modal-1.5.1 → modal-1.5.1.dev0}/modal/file_io.pyi +0 -0
  185. {modal-1.5.1 → modal-1.5.1.dev0}/modal/file_pattern_matcher.py +0 -0
  186. {modal-1.5.1 → modal-1.5.1.dev0}/modal/functions.py +0 -0
  187. {modal-1.5.1 → modal-1.5.1.dev0}/modal/image.py +0 -0
  188. {modal-1.5.1 → modal-1.5.1.dev0}/modal/image.pyi +0 -0
  189. {modal-1.5.1 → modal-1.5.1.dev0}/modal/io_streams.py +0 -0
  190. {modal-1.5.1 → modal-1.5.1.dev0}/modal/io_streams.pyi +0 -0
  191. {modal-1.5.1 → modal-1.5.1.dev0}/modal/mount.py +0 -0
  192. {modal-1.5.1 → modal-1.5.1.dev0}/modal/mount.pyi +0 -0
  193. {modal-1.5.1 → modal-1.5.1.dev0}/modal/network_file_system.py +0 -0
  194. {modal-1.5.1 → modal-1.5.1.dev0}/modal/network_file_system.pyi +0 -0
  195. {modal-1.5.1 → modal-1.5.1.dev0}/modal/object.py +0 -0
  196. {modal-1.5.1 → modal-1.5.1.dev0}/modal/object.pyi +0 -0
  197. {modal-1.5.1 → modal-1.5.1.dev0}/modal/output.py +0 -0
  198. {modal-1.5.1 → modal-1.5.1.dev0}/modal/parallel_map.py +0 -0
  199. {modal-1.5.1 → modal-1.5.1.dev0}/modal/parallel_map.pyi +0 -0
  200. {modal-1.5.1 → modal-1.5.1.dev0}/modal/partial_function.py +0 -0
  201. {modal-1.5.1 → modal-1.5.1.dev0}/modal/proxy.py +0 -0
  202. {modal-1.5.1 → modal-1.5.1.dev0}/modal/proxy.pyi +0 -0
  203. {modal-1.5.1 → modal-1.5.1.dev0}/modal/py.typed +0 -0
  204. {modal-1.5.1 → modal-1.5.1.dev0}/modal/queue.py +0 -0
  205. {modal-1.5.1 → modal-1.5.1.dev0}/modal/queue.pyi +0 -0
  206. {modal-1.5.1 → modal-1.5.1.dev0}/modal/retries.py +0 -0
  207. {modal-1.5.1 → modal-1.5.1.dev0}/modal/runner.pyi +0 -0
  208. {modal-1.5.1 → modal-1.5.1.dev0}/modal/running_app.py +0 -0
  209. {modal-1.5.1 → modal-1.5.1.dev0}/modal/sandbox_fs.pyi +0 -0
  210. {modal-1.5.1 → modal-1.5.1.dev0}/modal/scheduler_placement.py +0 -0
  211. {modal-1.5.1 → modal-1.5.1.dev0}/modal/server.py +0 -0
  212. {modal-1.5.1 → modal-1.5.1.dev0}/modal/serving.py +0 -0
  213. {modal-1.5.1 → modal-1.5.1.dev0}/modal/serving.pyi +0 -0
  214. {modal-1.5.1 → modal-1.5.1.dev0}/modal/skills/modal/SKILL.md +0 -0
  215. {modal-1.5.1 → modal-1.5.1.dev0}/modal/snapshot.py +0 -0
  216. {modal-1.5.1 → modal-1.5.1.dev0}/modal/snapshot.pyi +0 -0
  217. {modal-1.5.1 → modal-1.5.1.dev0}/modal/stream_type.py +0 -0
  218. {modal-1.5.1 → modal-1.5.1.dev0}/modal/token_flow.py +0 -0
  219. {modal-1.5.1 → modal-1.5.1.dev0}/modal/token_flow.pyi +0 -0
  220. {modal-1.5.1 → modal-1.5.1.dev0}/modal/volume.py +0 -0
  221. {modal-1.5.1 → modal-1.5.1.dev0}/modal/volume.pyi +0 -0
  222. {modal-1.5.1 → modal-1.5.1.dev0}/modal.egg-info/dependency_links.txt +0 -0
  223. {modal-1.5.1 → modal-1.5.1.dev0}/modal.egg-info/entry_points.txt +0 -0
  224. {modal-1.5.1 → modal-1.5.1.dev0}/modal.egg-info/top_level.txt +0 -0
  225. {modal-1.5.1 → modal-1.5.1.dev0}/modal_docs/__init__.py +0 -0
  226. {modal-1.5.1 → modal-1.5.1.dev0}/modal_docs/gen_cli_docs_main.py +0 -0
  227. {modal-1.5.1 → modal-1.5.1.dev0}/modal_docs/gen_reference_docs.py +0 -0
  228. {modal-1.5.1 → modal-1.5.1.dev0}/modal_docs/gen_reference_docs_main.py +0 -0
  229. {modal-1.5.1 → modal-1.5.1.dev0}/modal_docs/mdmd/__init__.py +0 -0
  230. {modal-1.5.1 → modal-1.5.1.dev0}/modal_docs/mdmd/signatures.py +0 -0
  231. {modal-1.5.1 → modal-1.5.1.dev0}/modal_proto/__init__.py +0 -0
  232. {modal-1.5.1 → modal-1.5.1.dev0}/modal_proto/py.typed +0 -0
  233. {modal-1.5.1 → modal-1.5.1.dev0}/modal_version/__main__.py +0 -0
  234. {modal-1.5.1 → modal-1.5.1.dev0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.5.1
3
+ Version: 1.5.1.dev0
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License-Expression: Apache-2.0
@@ -23,15 +23,12 @@ Requires-Dist: grpclib<0.4.10,>=0.4.7; python_version < "3.14"
23
23
  Requires-Dist: grpclib<0.4.10,>=0.4.9; python_version >= "3.14"
24
24
  Requires-Dist: protobuf!=4.24.0,<7.0,>=3.19
25
25
  Requires-Dist: rich>=12.0.0
26
- Requires-Dist: synchronicity~=0.12.5
26
+ Requires-Dist: synchronicity~=0.12.3
27
27
  Requires-Dist: toml
28
28
  Requires-Dist: types-certifi
29
29
  Requires-Dist: types-toml
30
30
  Requires-Dist: watchfiles
31
31
  Requires-Dist: typing_extensions~=4.6
32
- Provides-Extra: api-proxy-support
33
- Requires-Dist: python-socks[asyncio]>=2.5; extra == "api-proxy-support"
34
- Requires-Dist: aiohttp-socks>=0.8; extra == "api-proxy-support"
35
32
  Dynamic: license-file
36
33
 
37
34
  # Modal Python SDK
@@ -48,7 +45,7 @@ access to serverless cloud compute from Python scripts on your local computer.
48
45
  See the [online documentation](https://modal.com/docs/guide) for many
49
46
  [example applications](https://modal.com/docs/examples),
50
47
  a [user guide](https://modal.com/docs/guide), and the detailed
51
- [API reference](https://modal.com/docs/sdk/py/latest).
48
+ [API reference](https://modal.com/docs/reference).
52
49
 
53
50
  ## Installation
54
51
 
@@ -12,7 +12,7 @@ access to serverless cloud compute from Python scripts on your local computer.
12
12
  See the [online documentation](https://modal.com/docs/guide) for many
13
13
  [example applications](https://modal.com/docs/examples),
14
14
  a [user guide](https://modal.com/docs/guide), and the detailed
15
- [API reference](https://modal.com/docs/sdk/py/latest).
15
+ [API reference](https://modal.com/docs/reference).
16
16
 
17
17
  ## Installation
18
18
 
@@ -43,7 +43,6 @@ try:
43
43
  from .schedule import Cron, Period
44
44
  from .scheduler_placement import SchedulerPlacement
45
45
  from .secret import Secret
46
- from .server import Server
47
46
  from .snapshot import SandboxSnapshot
48
47
  from .volume import Volume
49
48
  from .workspace import Workspace
@@ -81,7 +80,6 @@ __all__ = [
81
80
  "SandboxSnapshot",
82
81
  "SchedulerPlacement",
83
82
  "Secret",
84
- "Server",
85
83
  "Tunnel",
86
84
  "Volume",
87
85
  "Workspace",
@@ -0,0 +1,94 @@
1
+ # Copyright Modal Labs 2025
2
+ from datetime import datetime, timezone
3
+ from decimal import Decimal
4
+ from typing import TypedDict
5
+
6
+ from modal_proto import api_pb2
7
+
8
+ from .client import _Client
9
+ from .exception import InvalidError
10
+
11
+
12
+ class WorkspaceBillingReportItem(TypedDict):
13
+ object_id: str
14
+ description: str
15
+ environment_name: str
16
+ interval_start: datetime
17
+ cost: Decimal
18
+ tags: dict[str, str]
19
+
20
+
21
+ async def _workspace_billing_report(
22
+ *,
23
+ start: datetime, # Start of the report, inclusive
24
+ end: datetime | None = None, # End of the report, exclusive
25
+ resolution: str = "d", # Resolution, e.g. "d" for daily or "h" for hourly
26
+ tag_names: list[str] | None = None, # Optional additional metadata to include
27
+ client: _Client | None = None,
28
+ ) -> list[WorkspaceBillingReportItem]:
29
+ """Generate a tabular report of workspace usage by object and time.
30
+
31
+ The result will be a list of dictionaries for each interval (determined by `resolution`)
32
+ between the `start` and `end` limits. The dictionary represents a single Modal object
33
+ that billing can be attributed to (e.g., an App) along with metadata (including user-defined
34
+ tags) for identifying that object.
35
+
36
+ The `start` and `end` parameters are required to either have a UTC timezone or to be
37
+ timezone-naive (which will be interpreted as UTC times). The timestamps in the result will
38
+ be in UTC. Cost will be reported for full intervals, even if the provided `start` or `end`
39
+ parameters are partial: `start` will be rounded to the beginning of its interval, while
40
+ partial `end` intervals will be excluded.
41
+
42
+ Additional user-provided metadata can be included in the report if the objects have tags
43
+ and `tag_names` (i.e., keys) are specified in the request. Alternatively, pass `tag_names=["*"]`
44
+ to include all tags in the report. Note that tags will be attributed to the entire interval even
45
+ if they were added or removed at some point within it. If the tag name was not in use during an
46
+ interval, it will be absent from the tags dictionary in that output row.
47
+
48
+ In most cases, billing data will be available in the database that this API queries within
49
+ minutes, although there may be collection delays. If completeness is important for your use
50
+ case, we recommend leaving a buffer after the end of the query interval.
51
+
52
+ It's also possible to generate reports using the
53
+ [`modal billing report`](https://modal.com/docs/reference/cli/billing) CLI command. The CLI
54
+ has a few convenience features for generating reports across relative time ranges.
55
+
56
+ """
57
+ if client is None:
58
+ client = await _Client.from_env()
59
+
60
+ tag_names = tag_names or []
61
+
62
+ if end is None:
63
+ end = datetime.now(timezone.utc)
64
+
65
+ if start.tzinfo is None:
66
+ start = start.replace(tzinfo=timezone.utc)
67
+ elif start.tzinfo != timezone.utc:
68
+ raise InvalidError("Timezone-aware 'start' parameter must be in UTC.")
69
+
70
+ if end.tzinfo is None:
71
+ end = end.replace(tzinfo=timezone.utc)
72
+ elif end.tzinfo != timezone.utc:
73
+ raise InvalidError("Timezone-aware 'end' parameter must be in UTC.")
74
+
75
+ request = api_pb2.WorkspaceBillingReportRequest(
76
+ resolution=resolution,
77
+ tag_names=tag_names,
78
+ )
79
+ request.start_timestamp.FromDatetime(start)
80
+ request.end_timestamp.FromDatetime(end)
81
+
82
+ rows = []
83
+ async for pb_item in client.stub.WorkspaceBillingReport.unary_stream(request):
84
+ item: WorkspaceBillingReportItem = {
85
+ "object_id": pb_item.object_id,
86
+ "description": pb_item.description,
87
+ "environment_name": pb_item.environment_name,
88
+ "interval_start": pb_item.interval.ToDatetime().replace(tzinfo=timezone.utc),
89
+ "cost": Decimal(pb_item.cost),
90
+ "tags": dict(pb_item.tags),
91
+ }
92
+ rows.append(item)
93
+
94
+ return rows
@@ -3,7 +3,6 @@ import asyncio
3
3
  import builtins
4
4
  from collections.abc import Iterable, Mapping
5
5
  from dataclasses import dataclass
6
- from datetime import datetime, timezone
7
6
  from typing import Literal
8
7
 
9
8
  from google.protobuf.empty_pb2 import Empty
@@ -13,7 +12,6 @@ from synchronicity import classproperty
13
12
 
14
13
  from modal_proto import api_pb2
15
14
 
16
- from ._billing import BillingReportItem
17
15
  from ._load_context import LoadContext
18
16
  from ._object import _Object
19
17
  from ._resolver import Resolver
@@ -320,7 +318,7 @@ class _Environment(_Object, type_prefix="en"):
320
318
  # def settings(self) -> EnvironmentSettings:
321
319
  # return self._settings
322
320
 
323
- def _hydrate_metadata(self, metadata: Message | None):
321
+ def _hydrate_metadata(self, metadata: Message):
324
322
  # Overridden concrete implementation of base class method
325
323
  assert metadata and isinstance(metadata, api_pb2.EnvironmentMetadata)
326
324
  self._name = metadata.name or None
@@ -394,87 +392,6 @@ class _Environment(_Object, type_prefix="en"):
394
392
  client=client,
395
393
  )
396
394
 
397
- @property
398
- def billing(self) -> "_EnvironmentBillingManager":
399
- return _EnvironmentBillingManager(self)
400
-
401
-
402
- class _EnvironmentBillingManager:
403
- """mdmd:namespace
404
- Namespace for Environment billing APIs
405
- """
406
-
407
- def __init__(self, environment: _Environment):
408
- """mdmd:ignore"""
409
- self._environment = environment
410
-
411
- async def report(
412
- self,
413
- *,
414
- start: datetime, # Start of the report, inclusive
415
- end: datetime | None = None, # End of the report, exclusive
416
- resolution: str = "d", # Resolution, e.g. "d" for daily or "h" for hourly
417
- tag_names: list[str] | None = None, # Optional additional metadata to include
418
- ) -> list[BillingReportItem]:
419
- """Return a cost report for Environment usage, broken down by object and time.
420
-
421
- Args:
422
- start: Start of the report, inclusive and rounded to the beginning of the interval.
423
- Must be in UTC or timezone-naive (interpreted as UTC).
424
- end: End of the report, exclusive. Must be in UTC or timezone-naive. Partial final
425
- intervals will be excluded from the report.
426
- resolution: Resolution, e.g. "d" for daily or "h" for hourly.
427
- tag_names: List of tag names; each row will include the tag name and value in use
428
- for that object during the relevant time interval. Pass `["*"]` to include all
429
- tags in the report.
430
-
431
- Returns:
432
- A list of `BillingReportItem` dataclasses. Each item reports the cost attributed to
433
- a specific Modal object during a given time interval. Cost is further broken down by
434
- the resource type that generated it (e.g. CPU, Memory, specific GPU usage).
435
- Note that the specific resource types included in the breakdown are subject to change
436
- as Modal's billing model evolves.
437
-
438
- See also:
439
- - [`modal environment billing report`](https://modal.com/docs/cli/latest/environment#modal-environment-billing-report):
440
- An environment report CLI that has convenience features around relative time range queries
441
- and JSON/CSV output.
442
- - [`Workspace.billing.report()`](https://modal.com/docs/sdk/py/latest/modal.Workspace#billingreport):
443
- An analogous report API for the entire Workspace.
444
-
445
- """
446
- if tag_names is None:
447
- tag_names = []
448
-
449
- if end is None:
450
- end = datetime.now(timezone.utc)
451
-
452
- if start.tzinfo is None:
453
- start = start.replace(tzinfo=timezone.utc)
454
- elif start.tzinfo != timezone.utc:
455
- raise InvalidError("Timezone-aware 'start' parameter must be in UTC.")
456
-
457
- if end.tzinfo is None:
458
- end = end.replace(tzinfo=timezone.utc)
459
- elif end.tzinfo != timezone.utc:
460
- raise InvalidError("Timezone-aware 'end' parameter must be in UTC.")
461
-
462
- if not self._environment.is_hydrated:
463
- await self._environment.hydrate()
464
-
465
- request = api_pb2.WorkspaceBillingReportRequest(
466
- resolution=resolution,
467
- tag_names=tag_names,
468
- environment_ids=[self._environment.object_id],
469
- )
470
- request.start_timestamp.FromDatetime(start)
471
- request.end_timestamp.FromDatetime(end)
472
-
473
- return [
474
- BillingReportItem._from_proto(pb_item)
475
- async for pb_item in self._environment.client.stub.WorkspaceBillingReport.unary_stream(request)
476
- ]
477
-
478
395
 
479
396
  ENVIRONMENT_CACHE: dict[str, _Environment] = {}
480
397
 
@@ -661,7 +661,6 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
661
661
  min_containers: int | None = None,
662
662
  max_containers: int | None = None,
663
663
  buffer_containers: int | None = None,
664
- scaleup_window: int | None = None,
665
664
  scaledown_window: int | None = None,
666
665
  max_concurrent_inputs: int | None = None,
667
666
  target_concurrent_inputs: int | None = None,
@@ -767,7 +766,6 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
767
766
  min_containers=min_containers,
768
767
  max_containers=max_containers,
769
768
  buffer_containers=buffer_containers,
770
- scaleup_window=scaleup_window,
771
769
  scaledown_window=scaledown_window,
772
770
  )
773
771
 
@@ -1159,7 +1157,6 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
1159
1157
  min_containers: int | None = None,
1160
1158
  max_containers: int | None = None,
1161
1159
  buffer_containers: int | None = None,
1162
- scaleup_window: int | None = None,
1163
1160
  scaledown_window: int | None = None,
1164
1161
  target_concurrency: int | None = None,
1165
1162
  ) -> None:
@@ -1167,7 +1164,6 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
1167
1164
  min_containers=min_containers,
1168
1165
  max_containers=max_containers,
1169
1166
  buffer_containers=buffer_containers,
1170
- scaleup_window=scaleup_window,
1171
1167
  scaledown_window=scaledown_window,
1172
1168
  target_concurrency=target_concurrency,
1173
1169
  )
@@ -1195,10 +1191,10 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
1195
1191
  its static configuration.
1196
1192
 
1197
1193
  Args:
1198
- min_containers: Minimum number of containers to keep running.
1199
- max_containers: Maximum concurrent containers.
1200
- buffer_containers: Extra containers to keep warm beyond current demand.
1201
- scaledown_window: Maximum duration (in seconds) idle containers wait before scaling down.
1194
+ min_containers: Minimum number of containers to keep running, or `None` to leave unchanged.
1195
+ max_containers: Maximum concurrent containers, or `None` to leave unchanged.
1196
+ buffer_containers: Extra containers to keep warm beyond demand, or `None` to leave unchanged.
1197
+ scaledown_window: Seconds idle containers wait before scaling down, or `None` to leave unchanged.
1202
1198
 
1203
1199
  Examples:
1204
1200
  ```python notest
@@ -1212,7 +1208,7 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
1212
1208
 
1213
1209
  # Extend the scaledown window to increase the amount of time that idle containers stay alive
1214
1210
  f.update_autoscaler(scaledown_window=300)
1215
- ```
1211
+ ```
1216
1212
 
1217
1213
  """
1218
1214
  # Assert .update_autoscaler() is not called on a method as opposed to the Object. Applicable for Cls only.
@@ -1912,9 +1908,9 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
1912
1908
  **kwargs: Keyword arguments forwarded to the remote function.
1913
1909
 
1914
1910
  Returns:
1915
- A [`modal.FunctionCall`](https://modal.com/docs/sdk/py/latest/modal.FunctionCall) object
1911
+ A [`modal.FunctionCall`](https://modal.com/docs/reference/modal.FunctionCall) object
1916
1912
  that can later be polled or waited for using
1917
- [`.get(timeout=...)`](https://modal.com/docs/sdk/py/latest/modal.FunctionCall#get).
1913
+ [`.get(timeout=...)`](https://modal.com/docs/reference/modal.FunctionCall#get).
1918
1914
  """
1919
1915
  self._check_no_web_url("spawn")
1920
1916
  if self._is_generator:
@@ -2065,7 +2061,7 @@ class _FunctionCall(typing.Generic[ReturnType], _Object, type_prefix="fc"):
2065
2061
  """Returns a structure representing the call graph from a given root
2066
2062
  call ID, along with the status of execution for each node.
2067
2063
 
2068
- See [`modal.call_graph`](https://modal.com/docs/sdk/py/latest/modal.call_graph) reference page
2064
+ See [`modal.call_graph`](https://modal.com/docs/reference/modal.call_graph) reference page
2069
2065
  for documentation on the structure of the returned `InputInfo` items.
2070
2066
 
2071
2067
  Returns:
@@ -2083,7 +2079,7 @@ class _FunctionCall(typing.Generic[ReturnType], _Object, type_prefix="fc"):
2083
2079
  terminate_containers: bool = False,
2084
2080
  ):
2085
2081
  """Cancels the function call, which will stop its execution and mark its inputs as
2086
- [`TERMINATED`](https://modal.com/docs/sdk/py/latest/modal.call_graph#modalcall_graphinputstatus).
2082
+ [`TERMINATED`](https://modal.com/docs/reference/modal.call_graph#modalcall_graphinputstatus).
2087
2083
 
2088
2084
  If `terminate_containers=True` - the containers running the cancelled inputs are all terminated
2089
2085
  causing any non-cancelled inputs on those containers to be rescheduled in new containers.
@@ -1,6 +1,6 @@
1
1
  # Copyright Modal Labs 2025
2
2
  from collections.abc import Collection, Mapping
3
- from typing import TYPE_CHECKING, Any, AsyncGenerator, Generic, Literal, TypeVar, overload
3
+ from typing import TYPE_CHECKING, Any, Generic, Literal, TypeVar, overload
4
4
 
5
5
  import grpclib.client
6
6
  from google.protobuf.message import Message
@@ -178,9 +178,9 @@ class UnaryStreamWrapper(Generic[RequestType, ResponseType]):
178
178
 
179
179
  async def unary_stream(
180
180
  self,
181
- request: RequestType,
181
+ request,
182
182
  metadata: Any | None = None,
183
- ) -> AsyncGenerator[ResponseType, None]:
183
+ ):
184
184
  from .client import _Client
185
185
 
186
186
  if self.client._snapshotted:
@@ -9,7 +9,6 @@ import typing
9
9
  import warnings
10
10
  from collections.abc import Callable, Collection, Sequence
11
11
  from dataclasses import dataclass, field
12
- from functools import wraps
13
12
  from inspect import isfunction
14
13
  from pathlib import Path, PurePosixPath
15
14
  from typing import (
@@ -425,20 +424,6 @@ async def _image_await_build_result(image_id: str, client: _Client) -> api_pb2.I
425
424
  return result_response
426
425
 
427
426
 
428
- def _requires_image_instance(method):
429
- @wraps(method)
430
- def wrapper(self, *args, **kwargs):
431
- if not isinstance(self, _Image):
432
- raise InvalidError(
433
- "Image has not been constructed yet. "
434
- f"Use one of the static factory methods prior to calling {method.__name__} "
435
- "like `modal.Image.debian_slim`, `modal.Image.from_registry`, or `modal.Image.micromamba`"
436
- )
437
- return method(self, *args, **kwargs)
438
-
439
- return wrapper
440
-
441
-
442
427
  class _Image(_Object, type_prefix="im"):
443
428
  """Base class for container images to run functions in.
444
429
 
@@ -770,7 +755,6 @@ class _Image(_Object, type_prefix="im"):
770
755
  context_mount_function=lambda: mount,
771
756
  )
772
757
 
773
- @_requires_image_instance
774
758
  def add_local_file(self, local_path: str | Path, remote_path: str, *, copy: bool = False) -> "_Image":
775
759
  """Adds a local file to the image at `remote_path` within the container.
776
760
 
@@ -807,7 +791,6 @@ class _Image(_Object, type_prefix="im"):
807
791
  mount = _Mount._from_local_file(local_path, remote_path)
808
792
  return self._add_mount_layer_or_copy(mount, copy=copy)
809
793
 
810
- @_requires_image_instance
811
794
  def add_local_dir(
812
795
  self,
813
796
  local_path: str | Path,
@@ -886,7 +869,6 @@ class _Image(_Object, type_prefix="im"):
886
869
  mount = _Mount._add_local_dir(Path(local_path), PurePosixPath(remote_path), ignore=_ignore_fn(ignore))
887
870
  return self._add_mount_layer_or_copy(mount, copy=copy)
888
871
 
889
- @_requires_image_instance
890
872
  def add_local_python_source(
891
873
  self, *modules: str, copy: bool = False, ignore: Sequence[str] | Callable[[Path], bool] = NON_PYTHON_FILES
892
874
  ) -> "_Image":
@@ -1030,7 +1012,6 @@ class _Image(_Object, type_prefix="im"):
1030
1012
  await resolver.load(self, load_context)
1031
1013
  return self
1032
1014
 
1033
- @_requires_image_instance
1034
1015
  def pip_install(
1035
1016
  self,
1036
1017
  *packages: str | list[str],
@@ -1117,7 +1098,6 @@ class _Image(_Object, type_prefix="im"):
1117
1098
  secrets=secrets,
1118
1099
  )
1119
1100
 
1120
- @_requires_image_instance
1121
1101
  def pip_install_private_repos(
1122
1102
  self,
1123
1103
  *repositories: str,
@@ -1238,7 +1218,6 @@ class _Image(_Object, type_prefix="im"):
1238
1218
  force_build=self.force_build or force_build,
1239
1219
  )
1240
1220
 
1241
- @_requires_image_instance
1242
1221
  def pip_install_from_requirements(
1243
1222
  self,
1244
1223
  requirements_txt: str,
@@ -1300,7 +1279,6 @@ class _Image(_Object, type_prefix="im"):
1300
1279
  secrets=secrets,
1301
1280
  )
1302
1281
 
1303
- @_requires_image_instance
1304
1282
  def pip_install_from_pyproject(
1305
1283
  self,
1306
1284
  pyproject_toml: str,
@@ -1384,7 +1362,6 @@ class _Image(_Object, type_prefix="im"):
1384
1362
  gpu_config=parse_gpu_config(gpu),
1385
1363
  )
1386
1364
 
1387
- @_requires_image_instance
1388
1365
  def uv_pip_install(
1389
1366
  self,
1390
1367
  *packages: str | list[str],
@@ -1516,7 +1493,6 @@ class _Image(_Object, type_prefix="im"):
1516
1493
  secrets=secrets,
1517
1494
  )
1518
1495
 
1519
- @_requires_image_instance
1520
1496
  def poetry_install_from_file(
1521
1497
  self,
1522
1498
  poetry_pyproject_toml: str,
@@ -1626,7 +1602,6 @@ class _Image(_Object, type_prefix="im"):
1626
1602
  gpu_config=parse_gpu_config(gpu),
1627
1603
  )
1628
1604
 
1629
- @_requires_image_instance
1630
1605
  def uv_sync(
1631
1606
  self,
1632
1607
  uv_project_dir: str = "./",
@@ -1810,7 +1785,6 @@ class _Image(_Object, type_prefix="im"):
1810
1785
  gpu_config=parse_gpu_config(gpu),
1811
1786
  )
1812
1787
 
1813
- @_requires_image_instance
1814
1788
  def dockerfile_commands(
1815
1789
  self,
1816
1790
  *dockerfile_commands: str | list[str],
@@ -1899,7 +1873,6 @@ class _Image(_Object, type_prefix="im"):
1899
1873
  build_args=build_args,
1900
1874
  )
1901
1875
 
1902
- @_requires_image_instance
1903
1876
  def entrypoint(
1904
1877
  self,
1905
1878
  entrypoint_commands: list[str],
@@ -1920,7 +1893,6 @@ class _Image(_Object, type_prefix="im"):
1920
1893
 
1921
1894
  return self.dockerfile_commands(dockerfile_cmd)
1922
1895
 
1923
- @_requires_image_instance
1924
1896
  def shell(
1925
1897
  self,
1926
1898
  shell_commands: list[str],
@@ -1941,7 +1913,6 @@ class _Image(_Object, type_prefix="im"):
1941
1913
 
1942
1914
  return self.dockerfile_commands(dockerfile_cmd)
1943
1915
 
1944
- @_requires_image_instance
1945
1916
  def run_commands(
1946
1917
  self,
1947
1918
  *commands: str | list[str],
@@ -2026,7 +1997,6 @@ class _Image(_Object, type_prefix="im"):
2026
1997
  _namespace=api_pb2.DEPLOYMENT_NAMESPACE_GLOBAL,
2027
1998
  )
2028
1999
 
2029
- @_requires_image_instance
2030
2000
  def micromamba_install(
2031
2001
  self,
2032
2002
  *packages: str | list[str],
@@ -2558,7 +2528,6 @@ class _Image(_Object, type_prefix="im"):
2558
2528
  _namespace=api_pb2.DEPLOYMENT_NAMESPACE_GLOBAL,
2559
2529
  )
2560
2530
 
2561
- @_requires_image_instance
2562
2531
  def apt_install(
2563
2532
  self,
2564
2533
  *packages: str | list[str],
@@ -2610,7 +2579,6 @@ class _Image(_Object, type_prefix="im"):
2610
2579
  secrets=secrets,
2611
2580
  )
2612
2581
 
2613
- @_requires_image_instance
2614
2582
  def run_function(
2615
2583
  self,
2616
2584
  raw_f: Callable[..., Any],
@@ -2729,7 +2697,6 @@ class _Image(_Object, type_prefix="im"):
2729
2697
  force_build=self.force_build or force_build,
2730
2698
  )
2731
2699
 
2732
- @_requires_image_instance
2733
2700
  def env(self, vars: dict[str, str]) -> "_Image":
2734
2701
  """Sets the environment variables in an Image.
2735
2702
 
@@ -2760,7 +2727,6 @@ class _Image(_Object, type_prefix="im"):
2760
2727
  dockerfile_function=build_dockerfile,
2761
2728
  )
2762
2729
 
2763
- @_requires_image_instance
2764
2730
  def workdir(self, path: str | PurePosixPath) -> "_Image":
2765
2731
  """Set the working directory for subsequent image build steps and function execution.
2766
2732
 
@@ -2790,7 +2756,6 @@ class _Image(_Object, type_prefix="im"):
2790
2756
  dockerfile_function=build_dockerfile,
2791
2757
  )
2792
2758
 
2793
- @_requires_image_instance
2794
2759
  def cmd(self, cmd: list[str]) -> "_Image":
2795
2760
  """Set the default command (`CMD`) to run when a container is started.
2796
2761
 
@@ -2819,7 +2784,6 @@ class _Image(_Object, type_prefix="im"):
2819
2784
 
2820
2785
  return self.dockerfile_commands(dockerfile_cmd)
2821
2786
 
2822
- @_requires_image_instance
2823
2787
  def pipe(
2824
2788
  self,
2825
2789
  func: Callable[Concatenate["modal.Image", P], "modal.Image"],
@@ -2965,16 +2929,17 @@ class _Image(_Object, type_prefix="im"):
2965
2929
  """
2966
2930
  tag = _parse_named_image_ref(name)
2967
2931
 
2968
- if self._object_id is None:
2932
+ if not self.is_hydrated:
2969
2933
  raise InvalidError("Cannot publish an image that has not been created yet. Call `.build()` first.")
2970
2934
 
2971
- _client = client or await _Client.from_env()
2935
+ _client = client or self._client
2936
+ assert _client is not None
2972
2937
 
2973
2938
  resolved_env = environment_name or config.get("environment") or ""
2974
2939
 
2975
2940
  await _client.stub.ImagePublish(
2976
2941
  api_pb2.ImagePublishRequest(
2977
- image_id=self._object_id,
2942
+ image_id=self.object_id,
2978
2943
  environment_name=resolved_env,
2979
2944
  is_public=False,
2980
2945
  tag=tag,
@@ -477,7 +477,7 @@ def _wsgi_app(
477
477
  Web Server Gateway Interface (WSGI) is a standard for synchronous Python web apps.
478
478
  It has been [succeeded by the ASGI interface](https://asgi.readthedocs.io/en/latest/introduction.html#wsgi-compatibility)
479
479
  which is compatible with ASGI and supports additional functionality such as web sockets.
480
- Modal supports ASGI via [`asgi_app`](https://modal.com/docs/sdk/py/latest/modal.asgi_app).
480
+ Modal supports ASGI via [`asgi_app`](https://modal.com/docs/reference/modal.asgi_app).
481
481
 
482
482
  Examples:
483
483
  ```python
@@ -17,11 +17,6 @@ from modal.config import config, logger
17
17
 
18
18
  CUDA_CHECKPOINT_PATH: str = config.get("cuda_checkpoint_path")
19
19
 
20
- # Exit code used to signal to modal-runtime that a GPU memory snapshot restore failed
21
- # and the task should be retried without a snapshot. This is a sentinel value that must
22
- # stay in sync with `GPU_SNAPSHOT_RESTORE_FAILED_EXIT_CODE` in runner.rs.
23
- SNAPSHOT_RESTORE_FAILED_EXIT_CODE: int = 222
24
-
25
20
  # Maximum total duration for each individual `cuda-checkpoint` invocation.
26
21
  CUDA_CHECKPOINT_TIMEOUT: float = 3 * 60.0
27
22
 
@@ -180,15 +180,10 @@ class _TaskLifecycleManager:
180
180
  if self.function_def._experimental_enable_gpu_snapshot and self.function_def.resources.gpu_config.gpu_type:
181
181
  logger.debug("GPU memory snapshot enabled. Attempting to restore GPU memory.")
182
182
 
183
- try:
184
- if self._cuda_checkpoint_session is None:
185
- raise gpu_memory_snapshot.CudaCheckpointException("CudaCheckpointSession not found")
186
- self._cuda_checkpoint_session.restore()
187
- except gpu_memory_snapshot.CudaCheckpointException as exc:
188
- logger.warning(f"GPU memory snapshot restore failed; retrying task without snapshot. Error: {exc}")
189
- sys.stderr.flush()
190
- # Exit with a sentinel code that the runtime will use to retry the task without a snapshot.
191
- os._exit(gpu_memory_snapshot.SNAPSHOT_RESTORE_FAILED_EXIT_CODE)
183
+ assert self._cuda_checkpoint_session, (
184
+ "CudaCheckpointSession not found when attempting to restore GPU memory"
185
+ )
186
+ self._cuda_checkpoint_session.restore()
192
187
 
193
188
  self._client = await _Client.from_env()
194
189