modal 1.5.6.dev18__tar.gz → 1.5.6.dev19__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 (239) hide show
  1. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/PKG-INFO +1 -1
  2. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/cli/app.py +76 -19
  3. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/cli/entry_point.py +1 -3
  4. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/client.pyi +2 -2
  5. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/config.py +1 -0
  6. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/functions.pyi +6 -6
  7. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/sandbox.py +57 -16
  8. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/sandbox.pyi +8 -0
  9. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal.egg-info/PKG-INFO +1 -1
  10. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal.egg-info/SOURCES.txt +0 -1
  11. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal_proto/api_pb2.py +528 -533
  12. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal_proto/api_pb2.pyi +9 -3
  13. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal_version/__init__.py +1 -1
  14. modal-1.5.6.dev18/modal/cli/bootstrap.py +0 -139
  15. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/LICENSE +0 -0
  16. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/README.md +0 -0
  17. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/__init__.py +0 -0
  18. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/__main__.py +0 -0
  19. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_billing.py +0 -0
  20. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_clustered_functions.py +0 -0
  21. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_clustered_functions.pyi +0 -0
  22. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_container_entrypoint.py +0 -0
  23. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_environments.py +0 -0
  24. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_function_variants.py +0 -0
  25. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_functions.py +0 -0
  26. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_grpc_client.py +0 -0
  27. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_image.py +0 -0
  28. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_ipython.py +0 -0
  29. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_load_context.py +0 -0
  30. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_location.py +0 -0
  31. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_logs.py +0 -0
  32. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_logs_manager.py +0 -0
  33. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_logs_manager.pyi +0 -0
  34. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_object.py +0 -0
  35. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_output/__init__.py +0 -0
  36. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_output/manager.py +0 -0
  37. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_output/pty.py +0 -0
  38. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_output/rich.py +0 -0
  39. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_output/status.py +0 -0
  40. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_partial_function.py +0 -0
  41. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_resolver.py +0 -0
  42. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_resources.py +0 -0
  43. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_runtime/__init__.py +0 -0
  44. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_runtime/asgi.py +0 -0
  45. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_runtime/container_io_manager.py +0 -0
  46. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_runtime/container_io_manager.pyi +0 -0
  47. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_runtime/execution_context.py +0 -0
  48. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_runtime/execution_context.pyi +0 -0
  49. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_runtime/gpu_memory_snapshot.py +0 -0
  50. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_runtime/task_lifecycle_manager.py +0 -0
  51. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_runtime/task_lifecycle_manager.pyi +0 -0
  52. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_runtime/telemetry.py +0 -0
  53. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_runtime/user_code_event_loop.py +0 -0
  54. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_runtime/user_code_imports.py +0 -0
  55. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_serialization.py +0 -0
  56. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_server.py +0 -0
  57. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_supports_logs.py +0 -0
  58. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_traceback.py +0 -0
  59. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_tunnel.py +0 -0
  60. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_tunnel.pyi +0 -0
  61. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_type_manager.py +0 -0
  62. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_utils/__init__.py +0 -0
  63. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_utils/app_utils.py +0 -0
  64. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_utils/async_utils.py +0 -0
  65. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_utils/auth_token_manager.py +0 -0
  66. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_utils/blob_utils.py +0 -0
  67. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_utils/browser_utils.py +0 -0
  68. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_utils/bytes_io_segment_payload.py +0 -0
  69. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_utils/curl_utils.py +0 -0
  70. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_utils/deprecation.py +0 -0
  71. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_utils/display_utils.py +0 -0
  72. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_utils/docker_utils.py +0 -0
  73. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_utils/function_utils.py +0 -0
  74. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_utils/git_utils.py +0 -0
  75. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_utils/grpc_testing.py +0 -0
  76. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_utils/grpc_utils.py +0 -0
  77. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_utils/hash_utils.py +0 -0
  78. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_utils/http_utils.py +0 -0
  79. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_utils/idle_countdown.py +0 -0
  80. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_utils/jwt_utils.py +0 -0
  81. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_utils/logger.py +0 -0
  82. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_utils/mount_utils.py +0 -0
  83. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_utils/name_utils.py +0 -0
  84. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_utils/package_utils.py +0 -0
  85. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_utils/pattern_utils.py +0 -0
  86. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_utils/proxy_support.py +0 -0
  87. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_utils/rand_pb_testing.py +0 -0
  88. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_utils/sandbox_fs_utils.py +0 -0
  89. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_utils/shell_utils.py +0 -0
  90. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_utils/task_command_router_client.py +0 -0
  91. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_utils/time_utils.py +0 -0
  92. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_vendor/__init__.py +0 -0
  93. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_vendor/a2wsgi_wsgi.py +0 -0
  94. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_vendor/cloudpickle.py +0 -0
  95. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_vendor/tblib.py +0 -0
  96. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_vendor/version.py +0 -0
  97. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_watcher.py +0 -0
  98. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/_workspace.py +0 -0
  99. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/app.py +0 -0
  100. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/app.pyi +0 -0
  101. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/billing.py +0 -0
  102. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/billing.pyi +0 -0
  103. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/builder/2023.12.312.txt +0 -0
  104. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/builder/2023.12.txt +0 -0
  105. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/builder/2024.04.txt +0 -0
  106. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/builder/2024.10.txt +0 -0
  107. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/builder/2025.06.txt +0 -0
  108. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/builder/PREVIEW.txt +0 -0
  109. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/builder/README.md +0 -0
  110. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/builder/base-images.json +0 -0
  111. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/call_graph.py +0 -0
  112. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/cli/__init__.py +0 -0
  113. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/cli/_download.py +0 -0
  114. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/cli/_help.py +0 -0
  115. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/cli/_logs.py +0 -0
  116. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/cli/_stats.py +0 -0
  117. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/cli/_traceback.py +0 -0
  118. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/cli/billing.py +0 -0
  119. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/cli/changelog.py +0 -0
  120. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/cli/cluster.py +0 -0
  121. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/cli/config.py +0 -0
  122. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/cli/container.py +0 -0
  123. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/cli/curl.py +0 -0
  124. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/cli/dashboard.py +0 -0
  125. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/cli/dict.py +0 -0
  126. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/cli/endpoint.py +0 -0
  127. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/cli/environment.py +0 -0
  128. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/cli/function.py +0 -0
  129. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/cli/image.py +0 -0
  130. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/cli/import_refs.py +0 -0
  131. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/cli/launch.py +0 -0
  132. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/cli/logo.py +0 -0
  133. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/cli/network_file_system.py +0 -0
  134. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/cli/profile.py +0 -0
  135. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/cli/programs/__init__.py +0 -0
  136. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/cli/programs/run_jupyter.py +0 -0
  137. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/cli/programs/vscode.py +0 -0
  138. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/cli/queues.py +0 -0
  139. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/cli/run.py +0 -0
  140. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/cli/secret.py +0 -0
  141. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/cli/selector.py +0 -0
  142. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/cli/server.py +0 -0
  143. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/cli/shell.py +0 -0
  144. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/cli/skills.py +0 -0
  145. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/cli/token.py +0 -0
  146. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/cli/utils.py +0 -0
  147. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/cli/volume.py +0 -0
  148. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/cli/workspace.py +0 -0
  149. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/client.py +0 -0
  150. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/cloud_bucket_mount.py +0 -0
  151. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/cloud_bucket_mount.pyi +0 -0
  152. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/cls.py +0 -0
  153. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/cls.pyi +0 -0
  154. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/container_process.py +0 -0
  155. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/container_process.pyi +0 -0
  156. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/dict.py +0 -0
  157. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/dict.pyi +0 -0
  158. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/environments.py +0 -0
  159. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/environments.pyi +0 -0
  160. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/exception.py +0 -0
  161. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/experimental/__init__.py +0 -0
  162. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/experimental/flash.py +0 -0
  163. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/experimental/flash.pyi +0 -0
  164. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/experimental/ipython.py +0 -0
  165. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/file_pattern_matcher.py +0 -0
  166. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/functions.py +0 -0
  167. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/image.py +0 -0
  168. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/image.pyi +0 -0
  169. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/io_streams.py +0 -0
  170. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/io_streams.pyi +0 -0
  171. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/mount.py +0 -0
  172. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/mount.pyi +0 -0
  173. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/network_file_system.py +0 -0
  174. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/network_file_system.pyi +0 -0
  175. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/object.py +0 -0
  176. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/object.pyi +0 -0
  177. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/output.py +0 -0
  178. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/parallel_map.py +0 -0
  179. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/parallel_map.pyi +0 -0
  180. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/partial_function.py +0 -0
  181. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/partial_function.pyi +0 -0
  182. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/proxy.py +0 -0
  183. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/proxy.pyi +0 -0
  184. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/py.typed +0 -0
  185. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/queue.py +0 -0
  186. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/queue.pyi +0 -0
  187. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/retries.py +0 -0
  188. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/runner.py +0 -0
  189. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/runner.pyi +0 -0
  190. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/running_app.py +0 -0
  191. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/sandbox_fs.py +0 -0
  192. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/sandbox_fs.pyi +0 -0
  193. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/schedule.py +0 -0
  194. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/scheduler_placement.py +0 -0
  195. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/secret.py +0 -0
  196. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/secret.pyi +0 -0
  197. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/server.py +0 -0
  198. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/server.pyi +0 -0
  199. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/serving.py +0 -0
  200. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/serving.pyi +0 -0
  201. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/skills/modal/SKILL.md +0 -0
  202. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/snapshot.py +0 -0
  203. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/snapshot.pyi +0 -0
  204. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/stream_type.py +0 -0
  205. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/token_flow.py +0 -0
  206. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/token_flow.pyi +0 -0
  207. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/types.py +0 -0
  208. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/volume.py +0 -0
  209. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/volume.pyi +0 -0
  210. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/workspace.py +0 -0
  211. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal/workspace.pyi +0 -0
  212. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal.egg-info/dependency_links.txt +0 -0
  213. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal.egg-info/entry_points.txt +0 -0
  214. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal.egg-info/requires.txt +0 -0
  215. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal.egg-info/top_level.txt +0 -0
  216. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal_docs/__init__.py +0 -0
  217. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal_docs/gen_cli_docs.py +0 -0
  218. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal_docs/gen_cli_docs_main.py +0 -0
  219. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal_docs/gen_reference_docs.py +0 -0
  220. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal_docs/gen_reference_docs_main.py +0 -0
  221. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal_docs/mdmd/__init__.py +0 -0
  222. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal_docs/mdmd/mdmd.py +0 -0
  223. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal_docs/mdmd/signatures.py +0 -0
  224. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal_docs/mdmd/types.py +0 -0
  225. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal_docs/reference_intro.md +0 -0
  226. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal_proto/__init__.py +0 -0
  227. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal_proto/api_grpc.py +0 -0
  228. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal_proto/api_pb2_grpc.py +0 -0
  229. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal_proto/api_pb2_grpc.pyi +0 -0
  230. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal_proto/modal_api_grpc.py +0 -0
  231. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal_proto/py.typed +0 -0
  232. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal_proto/task_command_router_grpc.py +0 -0
  233. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal_proto/task_command_router_pb2.py +0 -0
  234. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal_proto/task_command_router_pb2.pyi +0 -0
  235. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal_proto/task_command_router_pb2_grpc.py +0 -0
  236. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal_proto/task_command_router_pb2_grpc.pyi +0 -0
  237. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/modal_version/__main__.py +0 -0
  238. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/pyproject.toml +0 -0
  239. {modal-1.5.6.dev18 → modal-1.5.6.dev19}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.5.6.dev18
3
+ Version: 1.5.6.dev19
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License-Expression: Apache-2.0
@@ -3,13 +3,15 @@ import re
3
3
  import sys
4
4
  import time
5
5
  import warnings
6
+ from collections.abc import Mapping
6
7
  from json import dumps
7
8
  from typing import Literal, get_args
8
9
 
9
10
  import click
10
11
  import rich
11
12
  from click import UsageError
12
- from rich.table import Column
13
+ from google.protobuf.json_format import MessageToDict
14
+ from rich.table import Column, Table
13
15
  from rich.text import Text
14
16
 
15
17
  from modal._environments import ensure_env
@@ -620,8 +622,9 @@ async def dashboard(
620
622
  @click.argument("app_identifier")
621
623
  @env_option
622
624
  @click.option("--json", is_flag=True, default=False)
625
+ @click.option("--no-color", is_flag=True, default=False, help="Disable colors in the output.")
623
626
  @synchronizer.create_blocking
624
- async def info(app_identifier: str, *, env: str | None = None, json: bool = False):
627
+ async def info(app_identifier: str, *, env: str | None = None, json: bool = False, no_color: bool = False):
625
628
  """Show an App's lifecycle, Functions, and Servers.
626
629
 
627
630
  Examples:
@@ -650,6 +653,17 @@ async def info(app_identifier: str, *, env: str | None = None, json: bool = Fals
650
653
  state = APP_STATE_TO_MESSAGE.get(lifecycle.app_state, Text("unknown", style="gray"))
651
654
 
652
655
  if json:
656
+ summaries = {
657
+ function_id: MessageToDict(summary, preserving_proto_field_name=True)
658
+ for function_id, summary in resp.function_info_summaries.items()
659
+ }
660
+
661
+ def entries_with_info(entries: Mapping[str, str]) -> dict[str, dict]:
662
+ return {
663
+ name: {"id": function_id, "summary": summaries.get(function_id, {})}
664
+ for name, function_id in sorted(entries.items())
665
+ }
666
+
653
667
  output.print_json(
654
668
  dumps(
655
669
  {
@@ -665,28 +679,71 @@ async def info(app_identifier: str, *, env: str | None = None, json: bool = Fals
665
679
  "stopped_at": timestamp_to_localized_str(lifecycle.stopped_at, json),
666
680
  "stopped_by": lifecycle.stopped_by or None,
667
681
  },
668
- "functions": dict(sorted(app_info.functions.items())),
669
- "servers": dict(sorted(app_info.servers.items())),
682
+ "functions": entries_with_info(app_info.functions),
683
+ "servers": entries_with_info(app_info.servers),
670
684
  }
671
685
  )
672
686
  )
673
687
  return
674
688
 
675
- output.print(
676
- Text.assemble("App: ", (app_info.app_id, "bold"), " - ", (app_info.description, "bold"), " (", state, ")")
677
- )
689
+ header = Table(show_header=False, box=None, pad_edge=False, padding=(0, 1))
690
+ header.add_row(Text("App:"), Text(app_info.description))
691
+ header.add_row(Text("App ID:"), Text(app_info.app_id))
692
+ header.add_row(Text("State:"), Text(state.plain))
678
693
 
679
- if app_info.functions:
680
- display_table(["Name", "Function ID"], sorted(app_info.functions.items()), title="Functions")
681
- if app_info.servers:
682
- display_table(["Name", "Function ID"], sorted(app_info.servers.items()), title="Servers")
694
+ def event(label: str, timestamp: float, actor: str, version: int = 0) -> None:
695
+ parts = [timestamp_to_localized_str(timestamp, isotz=False), actor]
696
+ if version:
697
+ parts.insert(0, f"v{version}")
698
+ header.add_row(Text(label + ":"), Text(" · ".join(p for p in parts if p)))
683
699
 
684
- events: list[list[Text | str | None]] = [
685
- ["Created", timestamp_to_localized_str(lifecycle.created_at, json), lifecycle.created_by]
686
- ]
687
- if lifecycle.deployed_at:
688
- label = f"Deployed (v{lifecycle.version})" if lifecycle.version else "Deployed"
689
- events.append([label, timestamp_to_localized_str(lifecycle.deployed_at, json), lifecycle.deployed_by])
690
700
  if lifecycle.stopped_at:
691
- events.append(["Stopped", timestamp_to_localized_str(lifecycle.stopped_at, json), lifecycle.stopped_by])
692
- display_table(["Event", "Time", "By"], events, title="Lifecycle")
701
+ event("Stopped", lifecycle.stopped_at, lifecycle.stopped_by)
702
+ if lifecycle.deployed_at:
703
+ event("Deployment", lifecycle.deployed_at, lifecycle.deployed_by, lifecycle.version)
704
+ event("Created", lifecycle.created_at, lifecycle.created_by)
705
+ output.print(header)
706
+
707
+ name_width = max((len(name) for name in [*app_info.functions, *app_info.servers]), default=0)
708
+ for title, entries in (("Functions", app_info.functions), ("Servers", app_info.servers)):
709
+ if not entries:
710
+ continue
711
+ output.print("")
712
+ output.print(Text(f"{title} ({len(entries)}):"))
713
+ for index, (name, function_id) in enumerate(sorted(entries.items())):
714
+ if index:
715
+ output.print("")
716
+ identity = Table(show_header=False, box=None, pad_edge=False, padding=(0, 1))
717
+ identity.add_column(width=name_width + 2)
718
+ identity.add_column(no_wrap=True)
719
+ identity.add_row(Text(f" {name}"), Text(function_id))
720
+ output.print(identity)
721
+ if function_id not in resp.function_info_summaries:
722
+ continue
723
+ summary = resp.function_info_summaries[function_id]
724
+ hardware = [f"{gpu.count} × {gpu.gpu_type} GPU" for gpu in summary.gpu_config]
725
+ metadata = Text(f" {hardware[0] if hardware else 'CPU'}")
726
+ if len(hardware) > 1:
727
+ metadata.append(f" ({', '.join(hardware[1:])})", style=None if no_color else "bright_black")
728
+ if summary.web_function:
729
+ metadata.append(" · Web function")
730
+ if schedule := _app_function_schedule(summary.schedule):
731
+ metadata.append(" · ")
732
+ metadata.append(schedule)
733
+ if summary.HasField("requires_proxy_auth") and not summary.requires_proxy_auth:
734
+ metadata.append(" · ")
735
+ metadata.append("Unauthenticated", style=None if no_color else "yellow")
736
+ output.print(metadata)
737
+
738
+
739
+ def _app_function_schedule(schedule: api_pb2.Schedule) -> str | None:
740
+ if schedule.HasField("cron"):
741
+ return f"{schedule.cron.cron_string} ({schedule.cron.timezone or 'UTC'})"
742
+ if schedule.HasField("period"):
743
+ parts = [
744
+ f"{value:g} {field.name.removesuffix('s') if value == 1 else field.name}"
745
+ for field, value in schedule.period.ListFields()
746
+ if value
747
+ ]
748
+ return "Every " + ", ".join(parts)
749
+ return None
@@ -11,7 +11,6 @@ from . import run, shell as shell_module
11
11
  from ._help import ModalCommand, ModalGroup, ModalProfileOption
12
12
  from .app import app_cli
13
13
  from .billing import billing_cli
14
- from .bootstrap import bootstrap
15
14
  from .changelog import changelog
16
15
  from .cluster import cluster_cli
17
16
  from .config import config_cli
@@ -131,8 +130,6 @@ entrypoint_cli.add_command(secret_cli, panel="Storage")
131
130
  entrypoint_cli.add_command(queue_cli, panel="Storage")
132
131
  entrypoint_cli.add_command(volume_cli, panel="Storage")
133
132
 
134
- entrypoint_cli.add_command(setup, panel="Onboarding")
135
- entrypoint_cli.add_command(bootstrap, panel="Onboarding")
136
133
 
137
134
  entrypoint_cli.add_command(workspace_cli, panel="Configuration")
138
135
  entrypoint_cli.add_command(environment_cli, panel="Configuration")
@@ -140,6 +137,7 @@ entrypoint_cli.add_command(profile_cli, panel="Configuration")
140
137
  entrypoint_cli.add_command(config_cli, panel="Configuration")
141
138
  entrypoint_cli.add_command(token_cli, panel="Configuration")
142
139
  entrypoint_cli.add_command(skills_cli, panel="Configuration")
140
+ entrypoint_cli.add_command(setup, panel="Configuration")
143
141
 
144
142
  entrypoint_cli.add_command(billing_cli, panel="Observability")
145
143
  entrypoint_cli.add_command(changelog, panel="Observability")
@@ -77,7 +77,7 @@ class _Client:
77
77
  server_url: str,
78
78
  client_type: int,
79
79
  credentials: typing.Optional[tuple[str, str]],
80
- version: str = "1.5.6.dev18",
80
+ version: str = "1.5.6.dev19",
81
81
  *,
82
82
  oauth_credentials: typing.Optional[_OAuthCredentials] = None,
83
83
  ):
@@ -277,7 +277,7 @@ class Client:
277
277
  server_url: str,
278
278
  client_type: int,
279
279
  credentials: typing.Optional[tuple[str, str]],
280
- version: str = "1.5.6.dev18",
280
+ version: str = "1.5.6.dev19",
281
281
  *,
282
282
  oauth_credentials: typing.Optional[_OAuthCredentials] = None,
283
283
  ):
@@ -377,6 +377,7 @@ _SETTINGS = {
377
377
  "image_builder_version": _Setting(),
378
378
  "strict_parameters": _Setting(False, transform=_to_boolean), # For internal/experimental use
379
379
  "sandbox_v2": _Setting(None, transform=_to_boolean),
380
+ "use_control_plane_sidecar_create": _Setting(False, transform=_to_boolean), # For internal/experimental use
380
381
  "snapshot_debug": _Setting(False, transform=_to_boolean),
381
382
  "cuda_checkpoint_path": _Setting("/__modal/.bin/cuda-checkpoint"), # Used for snapshotting GPU memory.
382
383
  # Used to indicate gVisor cuda-checkpoint automation.
@@ -653,7 +653,7 @@ class Function(
653
653
 
654
654
  _call_generator: ___call_generator_spec
655
655
 
656
- class __remote_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER]):
656
+ class __remote_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER]):
657
657
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> ReturnType_INNER:
658
658
  """Calls the function remotely, executing it with the given arguments and returning the execution's result.
659
659
 
@@ -678,7 +678,7 @@ class Function(
678
678
  """
679
679
  ...
680
680
 
681
- remote: __remote_spec[modal._functions.ReturnType, modal._functions.P]
681
+ remote: __remote_spec[modal._functions.P, modal._functions.ReturnType]
682
682
 
683
683
  class __remote_gen_spec(typing_extensions.Protocol):
684
684
  def __call__(self, /, *args, **kwargs) -> typing.Generator[typing.Any, None, None]:
@@ -728,7 +728,7 @@ class Function(
728
728
  """
729
729
  ...
730
730
 
731
- class ___experimental_spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER]):
731
+ class ___experimental_spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER]):
732
732
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
733
733
  """[Experimental] Calls the function with the given arguments, without waiting for the results.
734
734
 
@@ -761,7 +761,7 @@ class Function(
761
761
  """
762
762
  ...
763
763
 
764
- _experimental_spawn: ___experimental_spawn_spec[modal._functions.ReturnType, modal._functions.P]
764
+ _experimental_spawn: ___experimental_spawn_spec[modal._functions.P, modal._functions.ReturnType]
765
765
 
766
766
  class ___spawn_map_inner_spec(typing_extensions.Protocol[P_INNER]):
767
767
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> None: ...
@@ -769,7 +769,7 @@ class Function(
769
769
 
770
770
  _spawn_map_inner: ___spawn_map_inner_spec[modal._functions.P]
771
771
 
772
- class __spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER]):
772
+ class __spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER]):
773
773
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
774
774
  """Calls the function with the given arguments, without waiting for the results.
775
775
 
@@ -802,7 +802,7 @@ class Function(
802
802
  """
803
803
  ...
804
804
 
805
- spawn: __spawn_spec[modal._functions.ReturnType, modal._functions.P]
805
+ spawn: __spawn_spec[modal._functions.P, modal._functions.ReturnType]
806
806
 
807
807
  def get_raw_f(self) -> collections.abc.Callable[..., typing.Any]:
808
808
  """Return the inner Python object wrapped by this Modal Function.
@@ -2979,6 +2979,15 @@ class _SidecarContainer:
2979
2979
  _MAIN_CONTAINER_NAME: str = "main"
2980
2980
 
2981
2981
 
2982
+ def _use_control_plane_sidecar_create(is_v2: bool) -> bool:
2983
+ """Whether a sidecar create request goes to the Modal server rather than over the Sandbox connection.
2984
+
2985
+ Opt-in via the `use_control_plane_sidecar_create` config setting. Only V2
2986
+ Sandboxes can; V1 Sandboxes always create sidecars over the Sandbox connection.
2987
+ """
2988
+ return is_v2 and config.get("use_control_plane_sidecar_create")
2989
+
2990
+
2982
2991
  class _SidecarManager:
2983
2992
  """Creates and manages sidecar containers in a Sandbox."""
2984
2993
 
@@ -3060,8 +3069,13 @@ class _SidecarManager:
3060
3069
  "or `.snapshot_filesystem()`\n"
3061
3070
  )
3062
3071
 
3063
- secrets = secrets or []
3064
- hydrate_coros = [secret.hydrate(client=self._sandbox._client) for secret in secrets] + [
3072
+ env_dict, resolvable_secrets = _split_env_dict_and_resolvable_secrets(list(secrets or []))
3073
+ if env:
3074
+ # `env` takes precedence over environment variables from secrets
3075
+ env_dict |= env
3076
+ _validate_sandbox_env(env_dict)
3077
+
3078
+ hydrate_coros = [secret.hydrate(client=self._sandbox._client) for secret in resolvable_secrets] + [
3065
3079
  volume.hydrate(client=self._sandbox._client) for _, volume in validated_volumes
3066
3080
  ]
3067
3081
  await TaskContext.gather(*hydrate_coros)
@@ -3073,21 +3087,48 @@ class _SidecarManager:
3073
3087
  # Relies on dicts being ordered (true as of Python 3.6).
3074
3088
  volume_mounts = [_volume_to_mount_proto(path, volume) for path, volume in validated_volumes]
3075
3089
 
3076
- task_id, command_router_client = await self._get_command_router()
3090
+ network_access = _build_outbound_network_access(False, outbound_cidr_allowlist, outbound_domain_allowlist)
3091
+ pty_info = _Sandbox._default_pty_info() if pty else None
3092
+
3093
+ if _use_control_plane_sidecar_create(self._sandbox._is_v2):
3094
+ definition = api_pb2.Sandbox(
3095
+ entrypoint_args=list(args),
3096
+ image_id=image.object_id,
3097
+ secret_ids=[secret.object_id for secret in resolvable_secrets],
3098
+ workdir=workdir,
3099
+ volume_mounts=volume_mounts,
3100
+ network_access=network_access,
3101
+ pty_info=pty_info,
3102
+ )
3103
+ create_req = api_pb2.SandboxContainerCreateV2Request(
3104
+ sandbox_id=self._sandbox.object_id,
3105
+ container_name=name,
3106
+ definition=definition,
3107
+ ephemeral_secrets=api_pb2.StringMap(contents=env_dict) if env_dict else None,
3108
+ )
3109
+ client = self._sandbox._client
3110
+ assert client._auth_token_manager
3111
+ auth_token = await client._auth_token_manager.get_token()
3112
+ create_resp = await client.stub.SandboxContainerCreateV2(
3113
+ create_req, metadata=[("x-modal-auth-token", auth_token)]
3114
+ )
3115
+ else:
3116
+ task_id, command_router_client = await self._get_command_router()
3117
+ create_resp = await command_router_client.container_create(
3118
+ sr_pb2.TaskContainerCreateRequest(
3119
+ task_id=task_id,
3120
+ container_name=name,
3121
+ image_id=image.object_id,
3122
+ args=list(args),
3123
+ env=env_dict,
3124
+ workdir=workdir or "",
3125
+ secret_ids=[secret.object_id for secret in resolvable_secrets],
3126
+ volume_mounts=volume_mounts,
3127
+ network_access=network_access,
3128
+ pty_info=pty_info,
3129
+ )
3130
+ )
3077
3131
 
3078
- create_req = sr_pb2.TaskContainerCreateRequest(
3079
- task_id=task_id,
3080
- container_name=name,
3081
- image_id=image.object_id,
3082
- args=list(args),
3083
- env=env or {},
3084
- workdir=workdir or "",
3085
- secret_ids=[secret.object_id for secret in secrets],
3086
- volume_mounts=volume_mounts,
3087
- network_access=_build_outbound_network_access(False, outbound_cidr_allowlist, outbound_domain_allowlist),
3088
- pty_info=_Sandbox._default_pty_info() if pty else None,
3089
- )
3090
- create_resp = await command_router_client.container_create(create_req)
3091
3132
  container_id = create_resp.container_id
3092
3133
  container_name = create_resp.container_name or name
3093
3134
  return _SidecarContainer(self._sandbox, container_id, container_name)
@@ -1222,6 +1222,14 @@ class _SidecarContainer:
1222
1222
  """
1223
1223
  ...
1224
1224
 
1225
+ def _use_control_plane_sidecar_create(is_v2: bool) -> bool:
1226
+ """Whether a sidecar create request goes to the Modal server rather than over the Sandbox connection.
1227
+
1228
+ Opt-in via the `use_control_plane_sidecar_create` config setting. Only V2
1229
+ Sandboxes can; V1 Sandboxes always create sidecars over the Sandbox connection.
1230
+ """
1231
+ ...
1232
+
1225
1233
  class _SidecarManager:
1226
1234
  """Creates and manages sidecar containers in a Sandbox."""
1227
1235
  def __init__(self, sandbox: _Sandbox) -> None:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.5.6.dev18
3
+ Version: 1.5.6.dev19
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License-Expression: Apache-2.0
@@ -173,7 +173,6 @@ modal/cli/_stats.py
173
173
  modal/cli/_traceback.py
174
174
  modal/cli/app.py
175
175
  modal/cli/billing.py
176
- modal/cli/bootstrap.py
177
176
  modal/cli/changelog.py
178
177
  modal/cli/cluster.py
179
178
  modal/cli/config.py