modal 1.4.4.dev22__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 (224) hide show
  1. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/PKG-INFO +1 -1
  2. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_environments.py +1 -1
  3. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/cli/image.py +7 -7
  4. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/cli/utils.py +8 -1
  5. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/client.pyi +2 -2
  6. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/sandbox.py +54 -11
  7. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/sandbox.pyi +12 -0
  8. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal.egg-info/PKG-INFO +1 -1
  9. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal_proto/api_pb2.py +421 -406
  10. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal_proto/api_pb2.pyi +21 -1
  11. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal_version/__init__.py +1 -1
  12. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/LICENSE +0 -0
  13. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/README.md +0 -0
  14. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/__init__.py +0 -0
  15. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/__main__.py +0 -0
  16. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_billing.py +0 -0
  17. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_clustered_functions.py +0 -0
  18. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_clustered_functions.pyi +0 -0
  19. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_container_entrypoint.py +0 -0
  20. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_function_variants.py +0 -0
  21. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_functions.py +0 -0
  22. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_grpc_client.py +0 -0
  23. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_image.py +0 -0
  24. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_ipython.py +0 -0
  25. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_load_context.py +0 -0
  26. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_location.py +0 -0
  27. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_logs.py +0 -0
  28. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_object.py +0 -0
  29. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_output/__init__.py +0 -0
  30. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_output/manager.py +0 -0
  31. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_output/pty.py +0 -0
  32. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_output/rich.py +0 -0
  33. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_output/status.py +0 -0
  34. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_partial_function.py +0 -0
  35. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_resolver.py +0 -0
  36. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_resources.py +0 -0
  37. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_runtime/__init__.py +0 -0
  38. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_runtime/asgi.py +0 -0
  39. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_runtime/container_io_manager.py +0 -0
  40. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_runtime/container_io_manager.pyi +0 -0
  41. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_runtime/execution_context.py +0 -0
  42. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_runtime/execution_context.pyi +0 -0
  43. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_runtime/gpu_memory_snapshot.py +0 -0
  44. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_runtime/task_lifecycle_manager.py +0 -0
  45. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_runtime/task_lifecycle_manager.pyi +0 -0
  46. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_runtime/telemetry.py +0 -0
  47. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_runtime/user_code_event_loop.py +0 -0
  48. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_runtime/user_code_imports.py +0 -0
  49. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_serialization.py +0 -0
  50. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_server.py +0 -0
  51. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_traceback.py +0 -0
  52. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_tunnel.py +0 -0
  53. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_tunnel.pyi +0 -0
  54. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_type_manager.py +0 -0
  55. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_utils/__init__.py +0 -0
  56. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_utils/app_utils.py +0 -0
  57. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_utils/async_utils.py +0 -0
  58. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_utils/auth_token_manager.py +0 -0
  59. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_utils/blob_utils.py +0 -0
  60. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_utils/browser_utils.py +0 -0
  61. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_utils/bytes_io_segment_payload.py +0 -0
  62. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_utils/deprecation.py +0 -0
  63. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_utils/docker_utils.py +0 -0
  64. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_utils/function_utils.py +0 -0
  65. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_utils/git_utils.py +0 -0
  66. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_utils/grpc_testing.py +0 -0
  67. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_utils/grpc_utils.py +0 -0
  68. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_utils/hash_utils.py +0 -0
  69. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_utils/http_utils.py +0 -0
  70. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_utils/jwt_utils.py +0 -0
  71. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_utils/logger.py +0 -0
  72. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_utils/mount_utils.py +0 -0
  73. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_utils/name_utils.py +0 -0
  74. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_utils/package_utils.py +0 -0
  75. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_utils/pattern_utils.py +0 -0
  76. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_utils/rand_pb_testing.py +0 -0
  77. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_utils/sandbox_fs_utils.py +0 -0
  78. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_utils/shell_utils.py +0 -0
  79. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_utils/task_command_router_client.py +0 -0
  80. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_utils/time_utils.py +0 -0
  81. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_vendor/__init__.py +0 -0
  82. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_vendor/a2wsgi_wsgi.py +0 -0
  83. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_vendor/cloudpickle.py +0 -0
  84. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_vendor/tblib.py +0 -0
  85. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_vendor/version.py +0 -0
  86. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_watcher.py +0 -0
  87. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/_workspace.py +0 -0
  88. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/app.py +0 -0
  89. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/app.pyi +0 -0
  90. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/billing.py +0 -0
  91. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/builder/2023.12.312.txt +0 -0
  92. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/builder/2023.12.txt +0 -0
  93. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/builder/2024.04.txt +0 -0
  94. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/builder/2024.10.txt +0 -0
  95. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/builder/2025.06.txt +0 -0
  96. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/builder/PREVIEW.txt +0 -0
  97. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/builder/README.md +0 -0
  98. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/builder/base-images.json +0 -0
  99. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/call_graph.py +0 -0
  100. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/cli/__init__.py +0 -0
  101. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/cli/_download.py +0 -0
  102. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/cli/_help.py +0 -0
  103. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/cli/_traceback.py +0 -0
  104. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/cli/app.py +0 -0
  105. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/cli/billing.py +0 -0
  106. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/cli/bootstrap.py +0 -0
  107. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/cli/changelog.py +0 -0
  108. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/cli/cluster.py +0 -0
  109. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/cli/config.py +0 -0
  110. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/cli/container.py +0 -0
  111. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/cli/dashboard.py +0 -0
  112. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/cli/dict.py +0 -0
  113. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/cli/entry_point.py +0 -0
  114. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/cli/environment.py +0 -0
  115. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/cli/import_refs.py +0 -0
  116. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/cli/launch.py +0 -0
  117. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/cli/logo.py +0 -0
  118. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/cli/network_file_system.py +0 -0
  119. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/cli/profile.py +0 -0
  120. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/cli/programs/__init__.py +0 -0
  121. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/cli/programs/run_jupyter.py +0 -0
  122. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/cli/programs/vscode.py +0 -0
  123. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/cli/queues.py +0 -0
  124. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/cli/run.py +0 -0
  125. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/cli/secret.py +0 -0
  126. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/cli/selector.py +0 -0
  127. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/cli/shell.py +0 -0
  128. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/cli/skills.py +0 -0
  129. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/cli/token.py +0 -0
  130. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/cli/volume.py +0 -0
  131. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/client.py +0 -0
  132. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/cloud_bucket_mount.py +0 -0
  133. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/cloud_bucket_mount.pyi +0 -0
  134. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/cls.py +0 -0
  135. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/cls.pyi +0 -0
  136. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/config.py +0 -0
  137. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/container_process.py +0 -0
  138. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/container_process.pyi +0 -0
  139. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/dict.py +0 -0
  140. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/dict.pyi +0 -0
  141. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/environments.py +0 -0
  142. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/environments.pyi +0 -0
  143. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/exception.py +0 -0
  144. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/experimental/__init__.py +0 -0
  145. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/experimental/flash.py +0 -0
  146. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/experimental/flash.pyi +0 -0
  147. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/experimental/ipython.py +0 -0
  148. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/file_io.py +0 -0
  149. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/file_io.pyi +0 -0
  150. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/file_pattern_matcher.py +0 -0
  151. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/functions.py +0 -0
  152. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/functions.pyi +0 -0
  153. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/image.py +0 -0
  154. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/image.pyi +0 -0
  155. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/io_streams.py +0 -0
  156. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/io_streams.pyi +0 -0
  157. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/mount.py +0 -0
  158. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/mount.pyi +0 -0
  159. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/network_file_system.py +0 -0
  160. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/network_file_system.pyi +0 -0
  161. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/object.py +0 -0
  162. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/object.pyi +0 -0
  163. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/output.py +0 -0
  164. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/parallel_map.py +0 -0
  165. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/parallel_map.pyi +0 -0
  166. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/partial_function.py +0 -0
  167. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/partial_function.pyi +0 -0
  168. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/proxy.py +0 -0
  169. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/proxy.pyi +0 -0
  170. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/py.typed +0 -0
  171. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/queue.py +0 -0
  172. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/queue.pyi +0 -0
  173. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/retries.py +0 -0
  174. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/runner.py +0 -0
  175. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/runner.pyi +0 -0
  176. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/running_app.py +0 -0
  177. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/sandbox_fs.py +0 -0
  178. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/sandbox_fs.pyi +0 -0
  179. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/schedule.py +0 -0
  180. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/scheduler_placement.py +0 -0
  181. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/secret.py +0 -0
  182. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/secret.pyi +0 -0
  183. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/server.py +0 -0
  184. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/server.pyi +0 -0
  185. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/serving.py +0 -0
  186. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/serving.pyi +0 -0
  187. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/skills/modal/SKILL.md +0 -0
  188. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/snapshot.py +0 -0
  189. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/snapshot.pyi +0 -0
  190. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/stream_type.py +0 -0
  191. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/token_flow.py +0 -0
  192. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/token_flow.pyi +0 -0
  193. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/volume.py +0 -0
  194. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/volume.pyi +0 -0
  195. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/workspace.py +0 -0
  196. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal/workspace.pyi +0 -0
  197. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal.egg-info/SOURCES.txt +0 -0
  198. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal.egg-info/dependency_links.txt +0 -0
  199. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal.egg-info/entry_points.txt +0 -0
  200. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal.egg-info/requires.txt +0 -0
  201. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal.egg-info/top_level.txt +0 -0
  202. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal_docs/__init__.py +0 -0
  203. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal_docs/gen_cli_docs.py +0 -0
  204. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal_docs/gen_cli_docs_main.py +0 -0
  205. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal_docs/gen_reference_docs.py +0 -0
  206. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal_docs/gen_reference_docs_main.py +0 -0
  207. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal_docs/mdmd/__init__.py +0 -0
  208. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal_docs/mdmd/mdmd.py +0 -0
  209. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal_docs/mdmd/signatures.py +0 -0
  210. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal_docs/mdmd/types.py +0 -0
  211. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal_proto/__init__.py +0 -0
  212. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal_proto/api_grpc.py +0 -0
  213. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal_proto/api_pb2_grpc.py +0 -0
  214. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal_proto/api_pb2_grpc.pyi +0 -0
  215. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal_proto/modal_api_grpc.py +0 -0
  216. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal_proto/py.typed +0 -0
  217. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal_proto/task_command_router_grpc.py +0 -0
  218. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal_proto/task_command_router_pb2.py +0 -0
  219. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal_proto/task_command_router_pb2.pyi +0 -0
  220. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal_proto/task_command_router_pb2_grpc.py +0 -0
  221. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal_proto/task_command_router_pb2_grpc.pyi +0 -0
  222. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/modal_version/__main__.py +0 -0
  223. {modal-1.4.4.dev22 → modal-1.5.1.dev0}/pyproject.toml +0 -0
  224. {modal-1.4.4.dev22 → 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.4.4.dev22
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
@@ -104,7 +104,7 @@ class _EnvironmentManager:
104
104
  MemberRole = Literal["viewer", "contributor"]
105
105
 
106
106
 
107
- def _role_to_proto(role: str) -> api_pb2.EnvironmentRole.ValueType:
107
+ def _role_to_proto(role: str) -> "api_pb2.EnvironmentRole.ValueType":
108
108
  match role:
109
109
  case "viewer":
110
110
  return api_pb2.ENVIRONMENT_ROLE_VIEWER
@@ -19,12 +19,12 @@ from modal_proto import api_pb2
19
19
 
20
20
  from ._help import ModalGroup
21
21
 
22
- IMAGE_REGISTRY_LIST_PAGE_SIZE = 100
23
- IMAGE_REGISTRY_LIST_PAGE_DELAY_SECONDS = 1.0
22
+ IMAGE_NAMES_LIST_PAGE_SIZE = 100
23
+ IMAGE_NAMES_LIST_PAGE_DELAY_SECONDS = 1.0
24
24
 
25
25
  image_cli = ModalGroup(name="image", help="Manage Images.")
26
- image_registry_cli = ModalGroup(name="registry", help="Manage the Modal Image name/tag registry.")
27
- image_cli.add_command(image_registry_cli)
26
+ image_names_cli = ModalGroup(name="names", help="Manage Modal Image names.")
27
+ image_cli.add_command(image_names_cli)
28
28
 
29
29
 
30
30
  def _print_result_summary(count: int) -> None:
@@ -60,7 +60,7 @@ async def _iter_tag_pages(
60
60
  api_pb2.ImageListTagsRequest(
61
61
  environment_name=env,
62
62
  tag_prefix=prefix,
63
- max_objects=IMAGE_REGISTRY_LIST_PAGE_SIZE,
63
+ max_objects=IMAGE_NAMES_LIST_PAGE_SIZE,
64
64
  page_token=page_token,
65
65
  )
66
66
  )
@@ -70,10 +70,10 @@ async def _iter_tag_pages(
70
70
  page_token = response.next_page_token
71
71
  if not page_token:
72
72
  return
73
- await asyncio.sleep(IMAGE_REGISTRY_LIST_PAGE_DELAY_SECONDS)
73
+ await asyncio.sleep(IMAGE_NAMES_LIST_PAGE_DELAY_SECONDS)
74
74
 
75
75
 
76
- @image_registry_cli.command("list", help="List named Images.")
76
+ @image_names_cli.command("list", help="List named Images.")
77
77
  @env_option
78
78
  @click.option("--prefix", default="", help="Only include named image tags that start with this prefix.")
79
79
  @click.option("--json", is_flag=True, default=False)
@@ -1,6 +1,7 @@
1
1
  # Copyright Modal Labs 2022
2
2
  import asyncio
3
3
  import io
4
+ import re
4
5
  import sys
5
6
  from collections.abc import Sequence
6
7
  from contextlib import nullcontext
@@ -126,6 +127,11 @@ def _plain(text: Text | str) -> str:
126
127
  return text.plain if isinstance(text, Text) else text
127
128
 
128
129
 
130
+ def _col_name_to_json_key(name: str) -> str:
131
+ """Convert a display column name like "App ID" to a snake_case JSON key like "app_id"."""
132
+ return re.sub(r"[^a-zA-Z0-9]+", "_", name).lower().strip("_")
133
+
134
+
129
135
  def is_tty() -> bool:
130
136
  return OutputManager.get().is_terminal
131
137
 
@@ -145,7 +151,8 @@ def display_table(
145
151
 
146
152
  output = OutputManager.get()
147
153
  if json:
148
- json_data = [{col_to_str(col): _plain(row[i]) for i, col in enumerate(columns)} for row in rows]
154
+ json_keys = [_col_name_to_json_key(col_to_str(col)) for col in columns]
155
+ json_data = [{json_keys[i]: _plain(row[i]) for i in range(len(columns))} for row in rows]
149
156
  output.print_json(dumps(json_data))
150
157
  elif csv:
151
158
  csv_buffer = io.StringIO()
@@ -35,7 +35,7 @@ class _Client:
35
35
  server_url: str,
36
36
  client_type: int,
37
37
  credentials: typing.Optional[tuple[str, str]],
38
- version: str = "1.4.4.dev22",
38
+ version: str = "1.5.1.dev0",
39
39
  ):
40
40
  """mdmd:hidden
41
41
  The Modal client object is not intended to be instantiated directly by users.
@@ -205,7 +205,7 @@ class Client:
205
205
  server_url: str,
206
206
  client_type: int,
207
207
  credentials: typing.Optional[tuple[str, str]],
208
- version: str = "1.4.4.dev22",
208
+ version: str = "1.5.1.dev0",
209
209
  ):
210
210
  """mdmd:hidden
211
211
  The Modal client object is not intended to be instantiated directly by users.
@@ -3,12 +3,13 @@ import asyncio
3
3
  import builtins
4
4
  import enum
5
5
  import json
6
+ import logging
6
7
  import os
7
8
  import time
8
9
  import typing
9
10
  import uuid
10
11
  import weakref
11
- from collections.abc import AsyncGenerator, AsyncIterator, Collection, Sequence
12
+ from collections.abc import AsyncGenerator, AsyncIterator, Awaitable, Collection, Sequence
12
13
  from dataclasses import dataclass
13
14
  from pathlib import PurePosixPath
14
15
  from typing import TYPE_CHECKING, Any, Literal, Union, overload
@@ -71,6 +72,42 @@ from .stream_type import StreamType
71
72
  _default_image: _Image = _Image.debian_slim()
72
73
 
73
74
 
75
+ async def _gather_load_with_timings(
76
+ load_coros: Sequence[Awaitable[Any]],
77
+ ) -> list[tuple[str, float]]:
78
+ """Await all loader coroutines concurrently and return [(object_id, elapsed_seconds)] per load."""
79
+ timings: list[tuple[str, float]] = []
80
+
81
+ async def timed(coro: Awaitable[Any]) -> None:
82
+ start = time.monotonic()
83
+ obj = await coro
84
+ timings.append((obj.object_id, time.monotonic() - start))
85
+
86
+ await asyncio.gather(*(timed(c) for c in load_coros))
87
+ return timings
88
+
89
+
90
+ def _format_sandbox_create_timing_log(
91
+ sandbox_id: str,
92
+ total_seconds: float,
93
+ rpc_seconds: float,
94
+ dep_timings: Sequence[tuple[str, float]],
95
+ ) -> str:
96
+ """Format the Sandbox create debug log line, listing the slowest deps first."""
97
+ if dep_timings:
98
+ deps_sorted = sorted(dep_timings, key=lambda t: t[1], reverse=True)
99
+ shown = deps_sorted[:10]
100
+ dep_summary = ", ".join(f"{label}: {elapsed:.2f}s" for label, elapsed in shown)
101
+ if len(deps_sorted) > 10:
102
+ dep_summary += f", +{len(deps_sorted) - 10} more"
103
+ else:
104
+ dep_summary = "none"
105
+ return (
106
+ f"Sandbox {sandbox_id} created in {total_seconds:.2f}s "
107
+ f"(create rpc: {rpc_seconds:.2f}s; dependencies: {dep_summary})"
108
+ )
109
+
110
+
74
111
  # The maximum number of bytes that can be passed to an exec on Linux.
75
112
  # Though this is technically a 'server side' limit, it is unlikely to change.
76
113
  # getconf ARG_MAX will show this value on a host.
@@ -349,6 +386,7 @@ class _Sandbox(_Object, type_prefix="sb"):
349
386
  pty_info = _Sandbox._default_pty_info()
350
387
 
351
388
  async def _load(self: _Sandbox, resolver: Resolver, load_context: LoadContext, _existing_object_id: str | None):
389
+ load_start = time.monotonic()
352
390
  # An already-hydrated image (e.g. one returned by
353
391
  # `Sandbox.snapshot_directory`) is skipped — there's nothing to load.
354
392
  dep_tasks: list = []
@@ -365,8 +403,7 @@ class _Sandbox(_Object, type_prefix="sb"):
365
403
  dep_tasks.append(resolver.load(cloud_bucket_mount.secret, load_context))
366
404
  if proxy:
367
405
  dep_tasks.append(resolver.load(proxy, load_context))
368
- if dep_tasks:
369
- await asyncio.gather(*dep_tasks)
406
+ dep_timings = await _gather_load_with_timings(dep_tasks) if dep_tasks else []
370
407
 
371
408
  # Validate that the same volume (by object_id) isn't mounted at multiple paths
372
409
  validate_volumes_by_object_id(validated_volumes)
@@ -444,10 +481,16 @@ class _Sandbox(_Object, type_prefix="sb"):
444
481
  create_req = api_pb2.SandboxCreateRequest(
445
482
  app_id=load_context.app_id, definition=definition, tags=tag_protos
446
483
  )
484
+ rpc_start = time.monotonic()
447
485
  create_resp = await load_context.client.stub.SandboxCreate(create_req)
486
+ rpc_elapsed = time.monotonic() - rpc_start
448
487
  sandbox_id = create_resp.sandbox_id
449
488
  self._hydrate(sandbox_id, load_context.client, None)
450
489
 
490
+ if logger.isEnabledFor(logging.DEBUG):
491
+ total_elapsed = time.monotonic() - load_start
492
+ logger.debug(_format_sandbox_create_timing_log(sandbox_id, total_elapsed, rpc_elapsed, dep_timings))
493
+
451
494
  return _Sandbox._from_loader(_load, "Sandbox()", load_context_overrides=LoadContext.empty())
452
495
 
453
496
  @staticmethod
@@ -864,6 +907,7 @@ class _Sandbox(_Object, type_prefix="sb"):
864
907
  )
865
908
 
866
909
  async def _load(self: _Sandbox, resolver: Resolver, load_context: LoadContext, _existing_object_id: str | None):
910
+ load_start = time.monotonic()
867
911
  dep_tasks: list = []
868
912
  if not image._is_hydrated:
869
913
  dep_tasks.append(resolver.load(image, load_context))
@@ -874,8 +918,7 @@ class _Sandbox(_Object, type_prefix="sb"):
874
918
  for _, cloud_bucket_mount in cloud_bucket_mounts:
875
919
  if cloud_bucket_mount.secret:
876
920
  dep_tasks.append(resolver.load(cloud_bucket_mount.secret, load_context))
877
- if dep_tasks:
878
- await asyncio.gather(*dep_tasks)
921
+ dep_timings = await _gather_load_with_timings(dep_tasks) if dep_tasks else []
879
922
 
880
923
  validate_volumes_by_object_id(validated_volumes)
881
924
 
@@ -909,9 +952,11 @@ class _Sandbox(_Object, type_prefix="sb"):
909
952
  create_req = api_pb2.SandboxCreateV2Request(app_id=load_context.app_id, definition=definition)
910
953
  assert load_context.client._auth_token_manager
911
954
  auth_token = await load_context.client._auth_token_manager.get_token()
955
+ rpc_start = time.monotonic()
912
956
  create_resp = await load_context.client.stub.SandboxCreateV2(
913
957
  create_req, metadata=[("x-modal-auth-token", auth_token)]
914
958
  )
959
+ rpc_elapsed = time.monotonic() - rpc_start
915
960
  sandbox_id = create_resp.sandbox_id
916
961
  self._hydrate(sandbox_id, load_context.client, None)
917
962
  self._is_v2 = True
@@ -922,6 +967,10 @@ class _Sandbox(_Object, type_prefix="sb"):
922
967
  for t in create_resp.tunnels
923
968
  }
924
969
 
970
+ if logger.isEnabledFor(logging.DEBUG):
971
+ total_elapsed = time.monotonic() - load_start
972
+ logger.debug(_format_sandbox_create_timing_log(sandbox_id, total_elapsed, rpc_elapsed, dep_timings))
973
+
925
974
  obj = _Sandbox._from_loader(_load, "Sandbox()", load_context_overrides=LoadContext.empty())
926
975
 
927
976
  app_id: str | None = None
@@ -1247,8 +1296,6 @@ class _Sandbox(_Object, type_prefix="sb"):
1247
1296
  sandbox_session_2.filesystem.list_files("/user_project")
1248
1297
  ```
1249
1298
  """
1250
- self._ensure_v1("mount_image")
1251
-
1252
1299
  if not isinstance(image, _Image):
1253
1300
  raise TypeError(f"Sandbox.mount_image(image=...) expects an Image object, got {image!r}")
1254
1301
 
@@ -1299,8 +1346,6 @@ class _Sandbox(_Object, type_prefix="sb"):
1299
1346
  path: Absolute mount point directory to unmount.
1300
1347
 
1301
1348
  """
1302
- self._ensure_v1("unmount_image")
1303
-
1304
1349
  task_id = await self._get_task_id()
1305
1350
  command_router_client = await self._get_command_router_client(task_id)
1306
1351
 
@@ -1344,8 +1389,6 @@ class _Sandbox(_Object, type_prefix="sb"):
1344
1389
  sandbox_session_2.filesystem.list_files("/user_project")
1345
1390
  ```
1346
1391
  """
1347
- self._ensure_v1("snapshot_directory")
1348
-
1349
1392
  wire_ttl_seconds = _ttl_to_wire_ttl(ttl)
1350
1393
 
1351
1394
  task_id = await self._get_task_id()
@@ -29,6 +29,18 @@ import pathlib
29
29
  import typing
30
30
  import typing_extensions
31
31
 
32
+ async def _gather_load_with_timings(
33
+ load_coros: collections.abc.Sequence[collections.abc.Awaitable[typing.Any]],
34
+ ) -> list[tuple[str, float]]:
35
+ """Await all loader coroutines concurrently and return [(object_id, elapsed_seconds)] per load."""
36
+ ...
37
+
38
+ def _format_sandbox_create_timing_log(
39
+ sandbox_id: str, total_seconds: float, rpc_seconds: float, dep_timings: collections.abc.Sequence[tuple[str, float]]
40
+ ) -> str:
41
+ """Format the Sandbox create debug log line, listing the slowest deps first."""
42
+ ...
43
+
32
44
  def _ttl_to_wire_ttl(ttl: typing.Optional[int]) -> int:
33
45
  """Convert a TTL value to the wire format, validating the input."""
34
46
  ...
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.4.4.dev22
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