modal 1.5.3.dev5__tar.gz → 1.5.3.dev7__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 (231) hide show
  1. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/PKG-INFO +1 -1
  2. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_environments.py +7 -8
  3. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_functions.py +11 -15
  4. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_utils/task_command_router_client.py +127 -3
  5. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_workspace.py +11 -14
  6. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/cli/shell.py +20 -1
  7. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/client.pyi +2 -2
  8. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/container_process.py +13 -1
  9. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/container_process.pyi +27 -0
  10. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/environments.pyi +12 -10
  11. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/functions.pyi +20 -20
  12. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/runner.py +31 -9
  13. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/runner.pyi +8 -1
  14. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/sandbox.py +31 -16
  15. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/sandbox.pyi +10 -14
  16. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/sandbox_fs.py +33 -82
  17. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/sandbox_fs.pyi +26 -6
  18. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/workspace.pyi +22 -18
  19. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal.egg-info/PKG-INFO +1 -1
  20. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal_docs/gen_reference_docs.py +0 -1
  21. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal_docs/mdmd/mdmd.py +21 -4
  22. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal_docs/mdmd/types.py +1 -0
  23. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal_proto/api_pb2.py +117 -104
  24. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal_proto/api_pb2.pyi +22 -14
  25. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal_version/__init__.py +1 -1
  26. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/LICENSE +0 -0
  27. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/README.md +0 -0
  28. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/__init__.py +0 -0
  29. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/__main__.py +0 -0
  30. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_billing.py +0 -0
  31. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_clustered_functions.py +0 -0
  32. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_clustered_functions.pyi +0 -0
  33. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_container_entrypoint.py +0 -0
  34. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_function_variants.py +0 -0
  35. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_grpc_client.py +0 -0
  36. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_image.py +0 -0
  37. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_ipython.py +0 -0
  38. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_load_context.py +0 -0
  39. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_location.py +0 -0
  40. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_logs.py +0 -0
  41. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_object.py +0 -0
  42. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_output/__init__.py +0 -0
  43. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_output/manager.py +0 -0
  44. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_output/pty.py +0 -0
  45. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_output/rich.py +0 -0
  46. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_output/status.py +0 -0
  47. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_partial_function.py +0 -0
  48. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_resolver.py +0 -0
  49. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_resources.py +0 -0
  50. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_runtime/__init__.py +0 -0
  51. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_runtime/asgi.py +0 -0
  52. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_runtime/container_io_manager.py +0 -0
  53. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_runtime/container_io_manager.pyi +0 -0
  54. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_runtime/execution_context.py +0 -0
  55. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_runtime/execution_context.pyi +0 -0
  56. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_runtime/gpu_memory_snapshot.py +0 -0
  57. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_runtime/task_lifecycle_manager.py +0 -0
  58. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_runtime/task_lifecycle_manager.pyi +0 -0
  59. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_runtime/telemetry.py +0 -0
  60. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_runtime/user_code_event_loop.py +0 -0
  61. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_runtime/user_code_imports.py +0 -0
  62. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_serialization.py +0 -0
  63. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_server.py +0 -0
  64. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_traceback.py +0 -0
  65. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_tunnel.py +0 -0
  66. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_tunnel.pyi +0 -0
  67. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_type_manager.py +0 -0
  68. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_utils/__init__.py +0 -0
  69. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_utils/app_utils.py +0 -0
  70. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_utils/async_utils.py +0 -0
  71. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_utils/auth_token_manager.py +0 -0
  72. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_utils/blob_utils.py +0 -0
  73. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_utils/browser_utils.py +0 -0
  74. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_utils/bytes_io_segment_payload.py +0 -0
  75. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_utils/curl_utils.py +0 -0
  76. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_utils/deprecation.py +0 -0
  77. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_utils/docker_utils.py +0 -0
  78. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_utils/function_utils.py +0 -0
  79. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_utils/git_utils.py +0 -0
  80. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_utils/grpc_testing.py +0 -0
  81. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_utils/grpc_utils.py +0 -0
  82. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_utils/hash_utils.py +0 -0
  83. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_utils/http_utils.py +0 -0
  84. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_utils/jwt_utils.py +0 -0
  85. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_utils/logger.py +0 -0
  86. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_utils/mount_utils.py +0 -0
  87. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_utils/name_utils.py +0 -0
  88. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_utils/package_utils.py +0 -0
  89. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_utils/pattern_utils.py +0 -0
  90. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_utils/proxy_support.py +0 -0
  91. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_utils/rand_pb_testing.py +0 -0
  92. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_utils/sandbox_fs_utils.py +0 -0
  93. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_utils/shell_utils.py +0 -0
  94. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_utils/time_utils.py +0 -0
  95. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_vendor/__init__.py +0 -0
  96. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_vendor/a2wsgi_wsgi.py +0 -0
  97. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_vendor/cloudpickle.py +0 -0
  98. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_vendor/tblib.py +0 -0
  99. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_vendor/version.py +0 -0
  100. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/_watcher.py +0 -0
  101. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/app.py +0 -0
  102. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/app.pyi +0 -0
  103. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/billing.py +0 -0
  104. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/billing.pyi +0 -0
  105. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/builder/2023.12.312.txt +0 -0
  106. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/builder/2023.12.txt +0 -0
  107. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/builder/2024.04.txt +0 -0
  108. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/builder/2024.10.txt +0 -0
  109. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/builder/2025.06.txt +0 -0
  110. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/builder/PREVIEW.txt +0 -0
  111. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/builder/README.md +0 -0
  112. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/builder/base-images.json +0 -0
  113. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/call_graph.py +0 -0
  114. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/cli/__init__.py +0 -0
  115. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/cli/_download.py +0 -0
  116. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/cli/_help.py +0 -0
  117. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/cli/_traceback.py +0 -0
  118. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/cli/app.py +0 -0
  119. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/cli/billing.py +0 -0
  120. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/cli/bootstrap.py +0 -0
  121. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/cli/changelog.py +0 -0
  122. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/cli/cluster.py +0 -0
  123. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/cli/config.py +0 -0
  124. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/cli/container.py +0 -0
  125. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/cli/curl.py +0 -0
  126. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/cli/dashboard.py +0 -0
  127. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/cli/dict.py +0 -0
  128. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/cli/endpoint.py +0 -0
  129. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/cli/entry_point.py +0 -0
  130. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/cli/environment.py +0 -0
  131. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/cli/image.py +0 -0
  132. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/cli/import_refs.py +0 -0
  133. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/cli/launch.py +0 -0
  134. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/cli/logo.py +0 -0
  135. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/cli/network_file_system.py +0 -0
  136. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/cli/profile.py +0 -0
  137. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/cli/programs/__init__.py +0 -0
  138. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/cli/programs/run_jupyter.py +0 -0
  139. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/cli/programs/vscode.py +0 -0
  140. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/cli/queues.py +0 -0
  141. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/cli/run.py +0 -0
  142. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/cli/secret.py +0 -0
  143. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/cli/selector.py +0 -0
  144. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/cli/skills.py +0 -0
  145. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/cli/token.py +0 -0
  146. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/cli/utils.py +0 -0
  147. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/cli/volume.py +0 -0
  148. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/cli/workspace.py +0 -0
  149. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/client.py +0 -0
  150. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/cloud_bucket_mount.py +0 -0
  151. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/cloud_bucket_mount.pyi +0 -0
  152. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/cls.py +0 -0
  153. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/cls.pyi +0 -0
  154. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/config.py +0 -0
  155. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/dict.py +0 -0
  156. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/dict.pyi +0 -0
  157. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/environments.py +0 -0
  158. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/exception.py +0 -0
  159. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/experimental/__init__.py +0 -0
  160. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/experimental/flash.py +0 -0
  161. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/experimental/flash.pyi +0 -0
  162. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/experimental/ipython.py +0 -0
  163. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/file_io.py +0 -0
  164. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/file_io.pyi +0 -0
  165. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/file_pattern_matcher.py +0 -0
  166. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/functions.py +0 -0
  167. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/image.py +0 -0
  168. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/image.pyi +0 -0
  169. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/io_streams.py +0 -0
  170. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/io_streams.pyi +0 -0
  171. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/mount.py +0 -0
  172. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/mount.pyi +0 -0
  173. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/network_file_system.py +0 -0
  174. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/network_file_system.pyi +0 -0
  175. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/object.py +0 -0
  176. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/object.pyi +0 -0
  177. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/output.py +0 -0
  178. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/parallel_map.py +0 -0
  179. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/parallel_map.pyi +0 -0
  180. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/partial_function.py +0 -0
  181. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/partial_function.pyi +0 -0
  182. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/proxy.py +0 -0
  183. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/proxy.pyi +0 -0
  184. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/py.typed +0 -0
  185. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/queue.py +0 -0
  186. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/queue.pyi +0 -0
  187. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/retries.py +0 -0
  188. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/running_app.py +0 -0
  189. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/schedule.py +0 -0
  190. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/scheduler_placement.py +0 -0
  191. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/secret.py +0 -0
  192. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/secret.pyi +0 -0
  193. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/server.py +0 -0
  194. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/server.pyi +0 -0
  195. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/serving.py +0 -0
  196. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/serving.pyi +0 -0
  197. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/skills/modal/SKILL.md +0 -0
  198. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/snapshot.py +0 -0
  199. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/snapshot.pyi +0 -0
  200. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/stream_type.py +0 -0
  201. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/token_flow.py +0 -0
  202. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/token_flow.pyi +0 -0
  203. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/types.py +0 -0
  204. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/volume.py +0 -0
  205. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/volume.pyi +0 -0
  206. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal/workspace.py +0 -0
  207. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal.egg-info/SOURCES.txt +0 -0
  208. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal.egg-info/dependency_links.txt +0 -0
  209. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal.egg-info/entry_points.txt +0 -0
  210. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal.egg-info/requires.txt +0 -0
  211. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal.egg-info/top_level.txt +0 -0
  212. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal_docs/__init__.py +0 -0
  213. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal_docs/gen_cli_docs.py +0 -0
  214. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal_docs/gen_cli_docs_main.py +0 -0
  215. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal_docs/gen_reference_docs_main.py +0 -0
  216. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal_docs/mdmd/__init__.py +0 -0
  217. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal_docs/mdmd/signatures.py +0 -0
  218. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal_proto/__init__.py +0 -0
  219. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal_proto/api_grpc.py +0 -0
  220. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal_proto/api_pb2_grpc.py +0 -0
  221. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal_proto/api_pb2_grpc.pyi +0 -0
  222. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal_proto/modal_api_grpc.py +0 -0
  223. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal_proto/py.typed +0 -0
  224. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal_proto/task_command_router_grpc.py +0 -0
  225. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal_proto/task_command_router_pb2.py +0 -0
  226. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal_proto/task_command_router_pb2.pyi +0 -0
  227. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal_proto/task_command_router_pb2_grpc.py +0 -0
  228. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal_proto/task_command_router_pb2_grpc.pyi +0 -0
  229. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/modal_version/__main__.py +0 -0
  230. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/pyproject.toml +0 -0
  231. {modal-1.5.3.dev5 → modal-1.5.3.dev7}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.5.3.dev5
3
+ Version: 1.5.3.dev7
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License-Expression: Apache-2.0
@@ -104,11 +104,7 @@ class _EnvironmentManager:
104
104
 
105
105
 
106
106
  class _EnvironmentMembersManager:
107
- """mdmd:namespace
108
- Namespace with methods for managing the membership of a restricted Environment.
109
-
110
- See https://modal.com/docs/guide/rbac for more information on restricted Environments.
111
- """
107
+ """mdmd:namespace"""
112
108
 
113
109
  def __init__(self, environment: "_Environment"):
114
110
  """mdmd:hidden"""
@@ -288,6 +284,10 @@ class _Environment(_Object, type_prefix="en"):
288
284
 
289
285
  @property
290
286
  def members(self) -> "_EnvironmentMembersManager":
287
+ """Namespace with methods for managing the membership of a restricted Environment.
288
+
289
+ See https://modal.com/docs/guide/rbac for more information on restricted Environments.
290
+ """
291
291
  return _EnvironmentMembersManager(self)
292
292
 
293
293
  # TODO(michael) Keeping this private for now until we decide what else should be in it
@@ -372,13 +372,12 @@ class _Environment(_Object, type_prefix="en"):
372
372
 
373
373
  @property
374
374
  def billing(self) -> "_EnvironmentBillingManager":
375
+ """Namespace for Environment billing APIs."""
375
376
  return _EnvironmentBillingManager(self)
376
377
 
377
378
 
378
379
  class _EnvironmentBillingManager:
379
- """mdmd:namespace
380
- Namespace for Environment billing APIs
381
- """
380
+ """mdmd:namespace"""
382
381
 
383
382
  def __init__(self, environment: _Environment):
384
383
  """mdmd:ignore"""
@@ -2073,11 +2073,13 @@ class _FunctionCall(typing.Generic[ReturnType], _Object, type_prefix="fc"):
2073
2073
 
2074
2074
  @live_method
2075
2075
  async def get_call_graph(self) -> list[InputInfo]:
2076
- """Returns a structure representing the call graph from a given root
2077
- call ID, along with the status of execution for each node.
2076
+ """Fetch information about the graph of Inputs this FunctionCall is part of.
2078
2077
 
2079
- See [`modal.call_graph`](https://modal.com/docs/sdk/py/latest/modal.call_graph) reference page
2080
- for documentation on the structure of the returned `InputInfo` items.
2078
+ Note: the call graph data is not populated in real-time, and its capture is best-effort.
2079
+ We do not recommend relying on this method for critical use cases.
2080
+
2081
+ See the [`modal.types`](/docs/sdk/py/latest/modal.types) reference for information
2082
+ on the return values.
2081
2083
 
2082
2084
  Returns:
2083
2085
  A list of `InputInfo` nodes describing the call graph.
@@ -2088,19 +2090,13 @@ class _FunctionCall(typing.Generic[ReturnType], _Object, type_prefix="fc"):
2088
2090
  return _reconstruct_call_graph(response)
2089
2091
 
2090
2092
  @live_method
2091
- async def cancel(
2092
- self,
2093
- # if true, containers running the inputs are forcibly terminated
2094
- terminate_containers: bool = False,
2095
- ):
2096
- """Cancels the function call, which will stop its execution and mark its inputs as
2097
- [`TERMINATED`](https://modal.com/docs/sdk/py/latest/modal.call_graph#modalcall_graphinputstatus).
2098
-
2099
- If `terminate_containers=True` - the containers running the cancelled inputs are all terminated
2100
- causing any non-cancelled inputs on those containers to be rescheduled in new containers.
2093
+ async def cancel(self, terminate_containers: bool = False):
2094
+ """Cancel the FunctionCall and terminate its inputs without retrying.
2101
2095
 
2102
2096
  Args:
2103
- terminate_containers: If True, forcibly terminate workers running cancelled inputs.
2097
+ terminate_containers: If True, terminate the containers running the cancelled
2098
+ inputs. Any other inputs running concurrently on those containers will be
2099
+ rescheduled.
2104
2100
  """
2105
2101
  request = api_pb2.FunctionCallCancelRequest(
2106
2102
  function_call_id=self.object_id, terminate_containers=terminate_containers
@@ -1,6 +1,7 @@
1
1
  # Copyright Modal Labs 2025
2
2
  import asyncio
3
3
  import base64
4
+ import io
4
5
  import json
5
6
  import socket
6
7
  import ssl
@@ -8,16 +9,16 @@ import time
8
9
  import typing
9
10
  import urllib.parse
10
11
  import weakref
11
- from collections.abc import AsyncGenerator, Callable
12
+ from collections.abc import AsyncGenerator, AsyncIterable, Callable
12
13
  from contextlib import suppress
13
- from typing import TypeVar
14
+ from typing import BinaryIO, TypeVar
14
15
 
15
16
  import grpclib.client
16
17
  from grpclib import GRPCError, Status
17
18
  from grpclib.exceptions import StreamTerminatedError
18
19
 
19
20
  from modal.config import logger
20
- from modal.exception import ExecTimeoutError, TimeoutError as ModalTimeoutError
21
+ from modal.exception import AuthError, ExecTimeoutError, InternalError, ServiceError, TimeoutError as ModalTimeoutError
21
22
  from modal_proto import api_pb2, task_command_router_pb2 as sr_pb2
22
23
  from modal_proto.task_command_router_grpc import TaskCommandRouterStub
23
24
 
@@ -26,6 +27,17 @@ from .._utils.grpc_utils import ModalChannel, create_channel_config
26
27
  from .async_utils import aclosing, retry
27
28
  from .grpc_utils import RETRYABLE_GRPC_STATUS_CODES
28
29
 
30
+ STREAMING_STDIN_CHUNK_SIZE = 256 * 1024
31
+
32
+ _STREAMING_STDIN_RESUMABLE_EXCEPTIONS = (
33
+ AuthError,
34
+ InternalError,
35
+ ServiceError,
36
+ StreamTerminatedError,
37
+ OSError,
38
+ asyncio.TimeoutError,
39
+ )
40
+
29
41
 
30
42
  @retry(n_attempts=34, base_delay=1, max_delay=10, attempt_timeout=10, total_timeout=310)
31
43
  async def _connect_channel(channel: grpclib.client.Channel):
@@ -468,6 +480,118 @@ class TaskCommandRouterClient:
468
480
  lambda: self._call_with_auth_retry(self._stub.TaskExecStdinWrite, request)
469
481
  )
470
482
 
483
+ async def exec_stdin_write_stream(
484
+ self,
485
+ task_id: str,
486
+ exec_id: str,
487
+ source: BinaryIO,
488
+ chunk_size: int = STREAMING_STDIN_CHUNK_SIZE,
489
+ max_resume_attempts: int = 9,
490
+ ) -> int:
491
+ """Stream `source` into the exec's stdin, with bounded resume on transient failures.
492
+
493
+ Streams the full contents of `source` in one client-streaming RPC and
494
+ closes stdin (EOF) on success. On a resumable error, queries
495
+ `exec_stdin_status` for the server's canonical offset, seeks `source`
496
+ to that point, and reopens the stream.
497
+
498
+ Args:
499
+ task_id: The task ID of the task running the exec'd command.
500
+ exec_id: The execution ID of the command to write to.
501
+ source: A seekable byte source (file, BytesIO, etc.).
502
+ chunk_size: Bytes per outbound message.
503
+ max_resume_attempts: Upper bound on resume retries before giving up.
504
+
505
+ Returns:
506
+ The total number of bytes streamed into the exec's stdin.
507
+ """
508
+ offset = 0
509
+ attempt = 0
510
+ while True:
511
+
512
+ async def _chunks():
513
+ while True:
514
+ chunk = source.read(chunk_size)
515
+ if not chunk:
516
+ return
517
+ yield chunk
518
+
519
+ try:
520
+ source.seek(offset)
521
+ await self._exec_stdin_write_stream(task_id, exec_id, offset, _chunks())
522
+ return source.tell()
523
+ except (*_STREAMING_STDIN_RESUMABLE_EXCEPTIONS, AttributeError) as e:
524
+ # StreamTerminatedError surfaces as AttributeError in grpclib<=0.4.7;
525
+ # see call_with_retries_on_transient_errors.
526
+ if isinstance(e, AttributeError) and "_write_appdata" not in str(e):
527
+ raise
528
+ attempt += 1
529
+ if attempt > max_resume_attempts:
530
+ raise
531
+ status = await self.exec_stdin_status(task_id=task_id, exec_id=exec_id)
532
+ if status.closed:
533
+ pos = source.tell()
534
+ if status.num_bytes_written == pos and source.seek(0, io.SEEK_END) == pos:
535
+ logger.debug(f"exec_stdin_write_stream completed but response was lost: {e}")
536
+ return pos
537
+ raise
538
+ offset = status.num_bytes_written
539
+ logger.debug(f"exec_stdin_write_stream resuming from offset {offset} after error: {e}")
540
+
541
+ async def _exec_stdin_write_stream(
542
+ self,
543
+ task_id: str,
544
+ exec_id: str,
545
+ start_offset: int,
546
+ chunks: AsyncIterable[bytes],
547
+ ) -> sr_pb2.TaskExecStdinWriteStreamResponse | None:
548
+ """Single client-streaming attempt: Start, Data chunks, then End (EOF).
549
+
550
+ Does not retry; `exec_stdin_write_stream` owns resume.
551
+ """
552
+ with grpc_error_converter():
553
+ stream = self._stub.TaskExecStdinWriteStream.open(metadata=self._get_metadata())
554
+ async with stream as s:
555
+ start = sr_pb2.TaskExecStdinWriteStreamRequest(
556
+ start=sr_pb2.TaskExecStdinWriteStreamStart(
557
+ task_id=task_id,
558
+ exec_id=exec_id,
559
+ offset=start_offset,
560
+ ),
561
+ )
562
+ await s.send_message(start)
563
+ async for data in chunks:
564
+ if not data:
565
+ continue
566
+ await s.send_message(sr_pb2.TaskExecStdinWriteStreamRequest(data=data))
567
+ # The server closes stdin only on this explicit End message. A
568
+ # stream that breaks before it leaves stdin open for resume.
569
+ await s.send_message(
570
+ sr_pb2.TaskExecStdinWriteStreamRequest(end=sr_pb2.TaskExecStdinWriteStreamEnd()),
571
+ end=True,
572
+ )
573
+ return await s.recv_message()
574
+
575
+ async def exec_stdin_status(self, task_id: str, exec_id: str) -> sr_pb2.TaskExecStdinStatusResponse:
576
+ """Read the current stdin write status for an exec'd command, to support retries from the right offset.
577
+
578
+ Used by streaming clients to find the resume offset after a stream
579
+ failure. Evicts any in-flight stdin stream for the exec, so it is not
580
+ safe to call for read-only observability.
581
+
582
+ Args:
583
+ task_id: The task ID of the task running the exec'd command.
584
+ exec_id: The execution ID of the command to query.
585
+ Raises:
586
+ Other errors: If retries are exhausted on transient errors or if there's an error
587
+ from the RPC itself.
588
+ """
589
+ request = sr_pb2.TaskExecStdinStatusRequest(task_id=task_id, exec_id=exec_id)
590
+ with grpc_error_converter():
591
+ return await call_with_retries_on_transient_errors(
592
+ lambda: self._call_with_auth_retry(self._stub.TaskExecStdinStatus, request)
593
+ )
594
+
471
595
  async def sandbox_stdin_write_v2(
472
596
  self, task_id: str, offset: int, data: bytes, eof: bool
473
597
  ) -> sr_pb2.SandboxStdinWriteV2Response:
@@ -35,9 +35,7 @@ def _member_role_from_proto(proto_value: int) -> str:
35
35
 
36
36
 
37
37
  class _WorkspaceMembersManager:
38
- """mdmd:namespace
39
- Namespace with methods for managing the membership of a Workspace.
40
- """
38
+ """mdmd:namespace"""
41
39
 
42
40
  def __init__(self, workspace: "_Workspace"):
43
41
  """mdmd:hidden"""
@@ -81,6 +79,7 @@ class _Workspace(_Object, type_prefix="ac"):
81
79
 
82
80
  @property
83
81
  def members(self) -> "_WorkspaceMembersManager":
82
+ """Namespace with methods for managing the membership of a Workspace."""
84
83
  return _WorkspaceMembersManager(self)
85
84
 
86
85
  @staticmethod
@@ -110,23 +109,25 @@ class _Workspace(_Object, type_prefix="ac"):
110
109
 
111
110
  @property
112
111
  def billing(self) -> "_WorkspaceBillingManager":
112
+ """Namespace for Workspace billing APIs."""
113
113
  return _WorkspaceBillingManager(self)
114
114
 
115
115
  @property
116
116
  def proxy_tokens(self) -> "_WorkspaceProxyTokenManager":
117
+ """Namespace with methods for managing the proxy tokens in a Workspace.
118
+
119
+ See [the guide](https://modal.com/docs/guide/webhook-proxy-auth) for more information on proxy tokens.
120
+ """
117
121
  return _WorkspaceProxyTokenManager(self)
118
122
 
119
123
  @property
120
124
  def settings(self) -> "_WorkspaceSettingsManager":
125
+ """Namespace for Workspace settings APIs."""
121
126
  return _WorkspaceSettingsManager(self)
122
127
 
123
128
 
124
129
  class _WorkspaceProxyTokenManager:
125
- """mdmd:namespace
126
- Namespace with methods for managing the proxy tokens in a Workspace.
127
-
128
- See [the guide](https://modal.com/docs/guide/webhook-proxy-auth) for more information on proxy tokens.
129
- """
130
+ """mdmd:namespace"""
130
131
 
131
132
  def __init__(self, workspace: "_Workspace"):
132
133
  """mdmd:hidden"""
@@ -245,9 +246,7 @@ class _WorkspaceProxyTokenManager:
245
246
 
246
247
 
247
248
  class _WorkspaceBillingManager:
248
- """mdmd:namespace
249
- Namespace for Workspace billing APIs.
250
- """
249
+ """mdmd:namespace"""
251
250
 
252
251
  def __init__(self, workspace: _Workspace):
253
252
  """mdmd:hidden"""
@@ -321,9 +320,7 @@ class _WorkspaceBillingManager:
321
320
 
322
321
 
323
322
  class _WorkspaceSettingsManager:
324
- """mdmd:namespace
325
- Namespace for Workspace settings APIs.
326
- """
323
+ """mdmd:namespace"""
327
324
 
328
325
  @classmethod
329
326
  def valid_settings(cls):
@@ -236,6 +236,7 @@ def _start_shell_from_image(
236
236
  region: str | None,
237
237
  pty: bool,
238
238
  experimental_options: dict[str, str],
239
+ v2: bool,
239
240
  ) -> None:
240
241
  volumes = {f"/mnt/{vol}": Volume.from_name(vol) for vol in volume}
241
242
  secrets = [Secret.from_name(s) for s in secret]
@@ -267,6 +268,7 @@ def _start_shell_from_image(
267
268
  region=region.split(",") if region else [],
268
269
  pty=pty,
269
270
  experimental_options=experimental_options,
271
+ v2=v2,
270
272
  )
271
273
 
272
274
 
@@ -327,6 +329,14 @@ def _start_shell_from_image(
327
329
  hidden=True,
328
330
  metavar="KEY=VALUE",
329
331
  )
332
+ @click.option(
333
+ "--experimental-v2",
334
+ "v2",
335
+ is_flag=True,
336
+ default=False,
337
+ hidden=True,
338
+ help="Create the shell using the V2 sandbox backend.",
339
+ )
330
340
  def shell(
331
341
  ref: str | None = None,
332
342
  cmd: str = "/bin/bash",
@@ -344,6 +354,7 @@ def shell(
344
354
  pty: bool | None = None,
345
355
  use_module_mode: bool = False,
346
356
  experimental_options: tuple[str, ...] = (),
357
+ v2: bool = False,
347
358
  ):
348
359
  """Run a command or interactive shell inside a Modal container.
349
360
 
@@ -423,13 +434,20 @@ def shell(
423
434
  shell.params,
424
435
  ctx,
425
436
  locals(),
426
- allowed=lambda p: p in {"cmd", "env", "pty", "ref", "use_module_mode", "experimental_options"},
437
+ allowed=lambda p: p in {"cmd", "env", "pty", "ref", "use_module_mode", "experimental_options", "v2"},
427
438
  ):
428
439
  raise ClickException(
429
440
  f"Cannot specify container configuration arguments ({', '.join(passed_forbidden)}) "
430
441
  f"when starting a new container from a function reference ('{ref}')."
431
442
  )
432
443
 
444
+ if v2:
445
+ # Function specs always carry mounts (e.g. the client mount), which the
446
+ # V2 backend does not support.
447
+ raise ClickException(
448
+ "--experimental-v2 is not supported when starting a shell from a function reference. "
449
+ "Use an image instead (e.g. `modal shell --experimental-v2 --image ...`)."
450
+ )
433
451
  function_spec = _function_spec_from_ref(ref, use_module_mode)
434
452
  _start_shell_from_function_spec(app, cmds, env, timeout, function_spec, pty, parsed_experimental_options)
435
453
  return
@@ -463,4 +481,5 @@ def shell(
463
481
  region,
464
482
  pty,
465
483
  parsed_experimental_options,
484
+ v2,
466
485
  )
@@ -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.3.dev5",
40
+ version: str = "1.5.3.dev7",
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.3.dev5",
210
+ version: str = "1.5.3.dev7",
211
211
  ):
212
212
  """mdmd:hidden
213
213
  The Modal client object is not intended to be instantiated directly by users.
@@ -1,7 +1,7 @@
1
1
  # Copyright Modal Labs 2024
2
2
  import asyncio
3
3
  import platform
4
- from typing import Generic, TypeVar
4
+ from typing import BinaryIO, Generic, TypeVar
5
5
 
6
6
  from modal_proto import api_pb2
7
7
 
@@ -117,6 +117,18 @@ class _ContainerProcess(Generic[T]):
117
117
  )
118
118
  return self._returncode
119
119
 
120
+ async def _stdin_write_stream(self, source: BinaryIO) -> int:
121
+ """mdmd:hidden
122
+ Stream `source` into the process's stdin and close it (EOF) on success.
123
+
124
+ Returns the total bytes streamed.
125
+ """
126
+ return await self._command_router_client.exec_stdin_write_stream(
127
+ task_id=self._task_id,
128
+ exec_id=self._process_id,
129
+ source=source,
130
+ )
131
+
120
132
  async def poll(self) -> int | None:
121
133
  """Check if the container process has finished running.
122
134
 
@@ -53,6 +53,14 @@ class _ContainerProcess(typing.Generic[T]):
53
53
 
54
54
  @property
55
55
  def returncode(self) -> int: ...
56
+ async def _stdin_write_stream(self, source: typing.BinaryIO) -> int:
57
+ """mdmd:hidden
58
+ Stream `source` into the process's stdin and close it (EOF) on success.
59
+
60
+ Returns the total bytes streamed.
61
+ """
62
+ ...
63
+
56
64
  async def poll(self) -> typing.Optional[int]:
57
65
  """Check if the container process has finished running.
58
66
 
@@ -105,6 +113,25 @@ class ContainerProcess(typing.Generic[T]):
105
113
  @property
106
114
  def returncode(self) -> int: ...
107
115
 
116
+ class ___stdin_write_stream_spec(typing_extensions.Protocol):
117
+ def __call__(self, /, source: typing.BinaryIO) -> int:
118
+ """mdmd:hidden
119
+ Stream `source` into the process's stdin and close it (EOF) on success.
120
+
121
+ Returns the total bytes streamed.
122
+ """
123
+ ...
124
+
125
+ async def aio(self, /, source: typing.BinaryIO) -> int:
126
+ """mdmd:hidden
127
+ Stream `source` into the process's stdin and close it (EOF) on success.
128
+
129
+ Returns the total bytes streamed.
130
+ """
131
+ ...
132
+
133
+ _stdin_write_stream: ___stdin_write_stream_spec
134
+
108
135
  class __poll_spec(typing_extensions.Protocol):
109
136
  def __call__(self, /) -> typing.Optional[int]:
110
137
  """Check if the container process has finished running.
@@ -102,11 +102,7 @@ class EnvironmentManager:
102
102
  delete: __delete_spec
103
103
 
104
104
  class EnvironmentMembersManager:
105
- """mdmd:namespace
106
- Namespace with methods for managing the membership of a restricted Environment.
107
-
108
- See https://modal.com/docs/guide/rbac for more information on restricted Environments.
109
- """
105
+ """mdmd:namespace"""
110
106
  def __init__(self, environment: Environment):
111
107
  """mdmd:hidden"""
112
108
  ...
@@ -254,9 +250,7 @@ class EnvironmentMembersManager:
254
250
  _dispatch_role_updates: ___dispatch_role_updates_spec
255
251
 
256
252
  class EnvironmentBillingManager:
257
- """mdmd:namespace
258
- Namespace for Environment billing APIs
259
- """
253
+ """mdmd:namespace"""
260
254
  def __init__(self, environment: Environment):
261
255
  """mdmd:ignore"""
262
256
  ...
@@ -352,7 +346,13 @@ class Environment(modal.object.Object):
352
346
  @classmethod
353
347
  def objects(cls) -> EnvironmentManager: ...
354
348
  @property
355
- def members(self) -> EnvironmentMembersManager: ...
349
+ def members(self) -> EnvironmentMembersManager:
350
+ """Namespace with methods for managing the membership of a restricted Environment.
351
+
352
+ See https://modal.com/docs/guide/rbac for more information on restricted Environments.
353
+ """
354
+ ...
355
+
356
356
  def _hydrate_metadata(self, metadata: typing.Optional[google.protobuf.message.Message]): ...
357
357
  @staticmethod
358
358
  def _get_or_create(
@@ -378,7 +378,9 @@ class Environment(modal.object.Object):
378
378
  ...
379
379
 
380
380
  @property
381
- def billing(self) -> EnvironmentBillingManager: ...
381
+ def billing(self) -> EnvironmentBillingManager:
382
+ """Namespace for Environment billing APIs."""
383
+ ...
382
384
 
383
385
  class __create_environment_spec(typing_extensions.Protocol):
384
386
  def __call__(self, /, name: str, client: typing.Optional[modal.client.Client] = None): ...
@@ -1044,11 +1044,13 @@ class FunctionCall(typing.Generic[modal._functions.ReturnType], modal.object.Obj
1044
1044
 
1045
1045
  class __get_call_graph_spec(typing_extensions.Protocol):
1046
1046
  def __call__(self, /) -> list[modal.types.InputInfo]:
1047
- """Returns a structure representing the call graph from a given root
1048
- call ID, along with the status of execution for each node.
1047
+ """Fetch information about the graph of Inputs this FunctionCall is part of.
1049
1048
 
1050
- See [`modal.call_graph`](https://modal.com/docs/sdk/py/latest/modal.call_graph) reference page
1051
- for documentation on the structure of the returned `InputInfo` items.
1049
+ Note: the call graph data is not populated in real-time, and its capture is best-effort.
1050
+ We do not recommend relying on this method for critical use cases.
1051
+
1052
+ See the [`modal.types`](/docs/sdk/py/latest/modal.types) reference for information
1053
+ on the return values.
1052
1054
 
1053
1055
  Returns:
1054
1056
  A list of `InputInfo` nodes describing the call graph.
@@ -1056,11 +1058,13 @@ class FunctionCall(typing.Generic[modal._functions.ReturnType], modal.object.Obj
1056
1058
  ...
1057
1059
 
1058
1060
  async def aio(self, /) -> list[modal.types.InputInfo]:
1059
- """Returns a structure representing the call graph from a given root
1060
- call ID, along with the status of execution for each node.
1061
+ """Fetch information about the graph of Inputs this FunctionCall is part of.
1062
+
1063
+ Note: the call graph data is not populated in real-time, and its capture is best-effort.
1064
+ We do not recommend relying on this method for critical use cases.
1061
1065
 
1062
- See [`modal.call_graph`](https://modal.com/docs/sdk/py/latest/modal.call_graph) reference page
1063
- for documentation on the structure of the returned `InputInfo` items.
1066
+ See the [`modal.types`](/docs/sdk/py/latest/modal.types) reference for information
1067
+ on the return values.
1064
1068
 
1065
1069
  Returns:
1066
1070
  A list of `InputInfo` nodes describing the call graph.
@@ -1071,26 +1075,22 @@ class FunctionCall(typing.Generic[modal._functions.ReturnType], modal.object.Obj
1071
1075
 
1072
1076
  class __cancel_spec(typing_extensions.Protocol):
1073
1077
  def __call__(self, /, terminate_containers: bool = False):
1074
- """Cancels the function call, which will stop its execution and mark its inputs as
1075
- [`TERMINATED`](https://modal.com/docs/sdk/py/latest/modal.call_graph#modalcall_graphinputstatus).
1076
-
1077
- If `terminate_containers=True` - the containers running the cancelled inputs are all terminated
1078
- causing any non-cancelled inputs on those containers to be rescheduled in new containers.
1078
+ """Cancel the FunctionCall and terminate its inputs without retrying.
1079
1079
 
1080
1080
  Args:
1081
- terminate_containers: If True, forcibly terminate workers running cancelled inputs.
1081
+ terminate_containers: If True, terminate the containers running the cancelled
1082
+ inputs. Any other inputs running concurrently on those containers will be
1083
+ rescheduled.
1082
1084
  """
1083
1085
  ...
1084
1086
 
1085
1087
  async def aio(self, /, terminate_containers: bool = False):
1086
- """Cancels the function call, which will stop its execution and mark its inputs as
1087
- [`TERMINATED`](https://modal.com/docs/sdk/py/latest/modal.call_graph#modalcall_graphinputstatus).
1088
-
1089
- If `terminate_containers=True` - the containers running the cancelled inputs are all terminated
1090
- causing any non-cancelled inputs on those containers to be rescheduled in new containers.
1088
+ """Cancel the FunctionCall and terminate its inputs without retrying.
1091
1089
 
1092
1090
  Args:
1093
- terminate_containers: If True, forcibly terminate workers running cancelled inputs.
1091
+ terminate_containers: If True, terminate the containers running the cancelled
1092
+ inputs. Any other inputs running concurrently on those containers will be
1093
+ rescheduled.
1094
1094
  """
1095
1095
  ...
1096
1096
 
@@ -690,7 +690,12 @@ async def _deploy_app(
690
690
 
691
691
 
692
692
  async def _interactive_shell(
693
- _app: "modal.app._App", cmds: list[str], environment_name: str = "", pty: bool = True, **kwargs: Any
693
+ _app: "modal.app._App",
694
+ cmds: list[str],
695
+ environment_name: str = "",
696
+ pty: bool = True,
697
+ v2: bool = False,
698
+ **kwargs: Any,
694
699
  ) -> None:
695
700
  """Run an interactive shell (like `bash`) within the image for this app.
696
701
 
@@ -732,13 +737,25 @@ async def _interactive_shell(
732
737
 
733
738
  # Temporarily enable output to show image build logs during sandbox creation
734
739
  output_mgr.set_quiet_mode(False)
735
- sandbox = await _Sandbox._create(
736
- "sleep",
737
- "100000",
738
- app=_app,
739
- secrets=secrets,
740
- **kwargs,
741
- )
740
+ if v2:
741
+ for option in ("gpu", "mounts", "network_file_systems"):
742
+ if kwargs.pop(option, None):
743
+ raise InvalidError(f"`{option}` is not supported for V2 sandboxes")
744
+ sandbox = await _Sandbox._experimental_create(
745
+ "sleep",
746
+ "100000",
747
+ app=_app,
748
+ secrets=secrets,
749
+ **kwargs,
750
+ )
751
+ else:
752
+ sandbox = await _Sandbox._create(
753
+ "sleep",
754
+ "100000",
755
+ app=_app,
756
+ secrets=secrets,
757
+ **kwargs,
758
+ )
742
759
 
743
760
  # Re-enable quiet mode before starting the interactive session
744
761
  output_mgr.set_quiet_mode(True)
@@ -757,7 +774,12 @@ async def _interactive_shell(
757
774
  except InteractiveTimeoutError:
758
775
  # Check on status of Sandbox. It may have crashed, causing connection failure.
759
776
  req = api_pb2.SandboxWaitRequest(sandbox_id=sandbox._object_id, timeout=0)
760
- resp = await sandbox._client.stub.SandboxWait(req)
777
+ if v2:
778
+ assert sandbox._client._auth_token_manager
779
+ auth_token = await sandbox._client._auth_token_manager.get_token()
780
+ resp = await sandbox._client.stub.SandboxWaitV2(req, metadata=[("x-modal-auth-token", auth_token)])
781
+ else:
782
+ resp = await sandbox._client.stub.SandboxWait(req)
761
783
  if resp.result.exception:
762
784
  raise RemoteError(resp.result.exception)
763
785
  else: