modal 1.4.2.dev0__tar.gz → 1.4.2.dev2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (209) hide show
  1. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/PKG-INFO +1 -1
  2. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_utils/rand_pb_testing.py +3 -1
  3. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_utils/task_command_router_client.py +69 -24
  4. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/app.py +2 -2
  5. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/app.pyi +4 -4
  6. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cli/app.py +67 -1
  7. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cli/import_refs.py +21 -2
  8. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cli/run.py +3 -3
  9. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cli/shell.py +1 -1
  10. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/client.pyi +2 -2
  11. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/config.py +2 -1
  12. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/functions.pyi +6 -6
  13. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/sandbox.py +7 -4
  14. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal.egg-info/PKG-INFO +1 -1
  15. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal_proto/api_grpc.py +48 -0
  16. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal_proto/api_pb2.py +1126 -1045
  17. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal_proto/api_pb2.pyi +148 -0
  18. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal_proto/api_pb2_grpc.py +100 -0
  19. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal_proto/api_pb2_grpc.pyi +32 -0
  20. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal_proto/modal_api_grpc.py +3 -0
  21. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal_proto/task_command_router_grpc.py +16 -0
  22. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal_proto/task_command_router_pb2.py +19 -9
  23. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal_proto/task_command_router_pb2.pyi +17 -0
  24. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal_proto/task_command_router_pb2_grpc.py +34 -0
  25. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal_proto/task_command_router_pb2_grpc.pyi +12 -0
  26. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal_version/__init__.py +1 -1
  27. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/LICENSE +0 -0
  28. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/README.md +0 -0
  29. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/__init__.py +0 -0
  30. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/__main__.py +0 -0
  31. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_billing.py +0 -0
  32. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_clustered_functions.py +0 -0
  33. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_clustered_functions.pyi +0 -0
  34. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_container_entrypoint.py +0 -0
  35. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_functions.py +0 -0
  36. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_grpc_client.py +0 -0
  37. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_ipython.py +0 -0
  38. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_load_context.py +0 -0
  39. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_location.py +0 -0
  40. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_logs.py +0 -0
  41. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_object.py +0 -0
  42. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_output/__init__.py +0 -0
  43. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_output/manager.py +0 -0
  44. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_output/pty.py +0 -0
  45. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_output/rich.py +0 -0
  46. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_output/status.py +0 -0
  47. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_partial_function.py +0 -0
  48. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_resolver.py +0 -0
  49. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_resources.py +0 -0
  50. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_runtime/__init__.py +0 -0
  51. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_runtime/asgi.py +0 -0
  52. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_runtime/container_io_manager.py +0 -0
  53. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_runtime/container_io_manager.pyi +0 -0
  54. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_runtime/execution_context.py +0 -0
  55. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_runtime/execution_context.pyi +0 -0
  56. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_runtime/gpu_memory_snapshot.py +0 -0
  57. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_runtime/telemetry.py +0 -0
  58. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_runtime/user_code_event_loop.py +0 -0
  59. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_runtime/user_code_imports.py +0 -0
  60. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_serialization.py +0 -0
  61. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_server.py +0 -0
  62. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_traceback.py +0 -0
  63. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_tunnel.py +0 -0
  64. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_tunnel.pyi +0 -0
  65. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_type_manager.py +0 -0
  66. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_utils/__init__.py +0 -0
  67. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_utils/app_utils.py +0 -0
  68. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_utils/async_utils.py +0 -0
  69. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_utils/auth_token_manager.py +0 -0
  70. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_utils/blob_utils.py +0 -0
  71. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_utils/browser_utils.py +0 -0
  72. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_utils/bytes_io_segment_payload.py +0 -0
  73. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_utils/deprecation.py +0 -0
  74. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_utils/docker_utils.py +0 -0
  75. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_utils/function_utils.py +0 -0
  76. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_utils/git_utils.py +0 -0
  77. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_utils/grpc_testing.py +0 -0
  78. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_utils/grpc_utils.py +0 -0
  79. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_utils/hash_utils.py +0 -0
  80. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_utils/http_utils.py +0 -0
  81. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_utils/jwt_utils.py +0 -0
  82. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_utils/logger.py +0 -0
  83. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_utils/mount_utils.py +0 -0
  84. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_utils/name_utils.py +0 -0
  85. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_utils/package_utils.py +0 -0
  86. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_utils/pattern_utils.py +0 -0
  87. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_utils/sandbox_fs_utils.py +0 -0
  88. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_utils/shell_utils.py +0 -0
  89. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_utils/time_utils.py +0 -0
  90. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_vendor/__init__.py +0 -0
  91. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_vendor/a2wsgi_wsgi.py +0 -0
  92. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_vendor/cloudpickle.py +0 -0
  93. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_vendor/tblib.py +0 -0
  94. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_vendor/version.py +0 -0
  95. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/_watcher.py +0 -0
  96. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/billing.py +0 -0
  97. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/builder/2023.12.312.txt +0 -0
  98. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/builder/2023.12.txt +0 -0
  99. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/builder/2024.04.txt +0 -0
  100. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/builder/2024.10.txt +0 -0
  101. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/builder/2025.06.txt +0 -0
  102. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/builder/PREVIEW.txt +0 -0
  103. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/builder/README.md +0 -0
  104. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/builder/base-images.json +0 -0
  105. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/call_graph.py +0 -0
  106. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cli/__init__.py +0 -0
  107. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cli/_download.py +0 -0
  108. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cli/_traceback.py +0 -0
  109. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cli/billing.py +0 -0
  110. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cli/changelog.py +0 -0
  111. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cli/cluster.py +0 -0
  112. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cli/config.py +0 -0
  113. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cli/container.py +0 -0
  114. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cli/dashboard.py +0 -0
  115. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cli/dict.py +0 -0
  116. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cli/entry_point.py +0 -0
  117. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cli/environment.py +0 -0
  118. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cli/launch.py +0 -0
  119. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cli/network_file_system.py +0 -0
  120. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cli/profile.py +0 -0
  121. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cli/programs/__init__.py +0 -0
  122. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cli/programs/run_jupyter.py +0 -0
  123. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cli/programs/vscode.py +0 -0
  124. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cli/queues.py +0 -0
  125. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cli/secret.py +0 -0
  126. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cli/selector.py +0 -0
  127. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cli/token.py +0 -0
  128. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cli/utils.py +0 -0
  129. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cli/volume.py +0 -0
  130. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/client.py +0 -0
  131. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cloud_bucket_mount.py +0 -0
  132. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cloud_bucket_mount.pyi +0 -0
  133. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cls.py +0 -0
  134. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/cls.pyi +0 -0
  135. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/container_process.py +0 -0
  136. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/container_process.pyi +0 -0
  137. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/dict.py +0 -0
  138. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/dict.pyi +0 -0
  139. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/environments.py +0 -0
  140. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/environments.pyi +0 -0
  141. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/exception.py +0 -0
  142. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/experimental/__init__.py +0 -0
  143. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/experimental/flash.py +0 -0
  144. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/experimental/flash.pyi +0 -0
  145. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/experimental/ipython.py +0 -0
  146. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/file_io.py +0 -0
  147. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/file_io.pyi +0 -0
  148. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/file_pattern_matcher.py +0 -0
  149. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/functions.py +0 -0
  150. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/image.py +0 -0
  151. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/image.pyi +0 -0
  152. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/io_streams.py +0 -0
  153. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/io_streams.pyi +0 -0
  154. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/mount.py +0 -0
  155. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/mount.pyi +0 -0
  156. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/network_file_system.py +0 -0
  157. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/network_file_system.pyi +0 -0
  158. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/object.py +0 -0
  159. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/object.pyi +0 -0
  160. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/output.py +0 -0
  161. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/parallel_map.py +0 -0
  162. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/parallel_map.pyi +0 -0
  163. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/partial_function.py +0 -0
  164. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/partial_function.pyi +0 -0
  165. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/proxy.py +0 -0
  166. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/proxy.pyi +0 -0
  167. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/py.typed +0 -0
  168. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/queue.py +0 -0
  169. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/queue.pyi +0 -0
  170. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/retries.py +0 -0
  171. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/runner.py +0 -0
  172. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/runner.pyi +0 -0
  173. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/running_app.py +0 -0
  174. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/sandbox.pyi +0 -0
  175. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/sandbox_fs.py +0 -0
  176. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/sandbox_fs.pyi +0 -0
  177. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/schedule.py +0 -0
  178. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/scheduler_placement.py +0 -0
  179. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/secret.py +0 -0
  180. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/secret.pyi +0 -0
  181. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/server.py +0 -0
  182. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/server.pyi +0 -0
  183. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/serving.py +0 -0
  184. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/serving.pyi +0 -0
  185. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/snapshot.py +0 -0
  186. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/snapshot.pyi +0 -0
  187. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/stream_type.py +0 -0
  188. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/token_flow.py +0 -0
  189. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/token_flow.pyi +0 -0
  190. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/volume.py +0 -0
  191. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal/volume.pyi +0 -0
  192. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal.egg-info/SOURCES.txt +0 -0
  193. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal.egg-info/dependency_links.txt +0 -0
  194. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal.egg-info/entry_points.txt +0 -0
  195. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal.egg-info/requires.txt +0 -0
  196. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal.egg-info/top_level.txt +0 -0
  197. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal_docs/__init__.py +0 -0
  198. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal_docs/gen_cli_docs.py +0 -0
  199. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal_docs/gen_cli_docs_main.py +0 -0
  200. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal_docs/gen_reference_docs.py +0 -0
  201. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal_docs/gen_reference_docs_main.py +0 -0
  202. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal_docs/mdmd/__init__.py +0 -0
  203. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal_docs/mdmd/mdmd.py +0 -0
  204. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal_docs/mdmd/signatures.py +0 -0
  205. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal_proto/__init__.py +0 -0
  206. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal_proto/py.typed +0 -0
  207. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/modal_version/__main__.py +0 -0
  208. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/pyproject.toml +0 -0
  209. {modal-1.4.2.dev0 → modal-1.4.2.dev2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.4.2.dev0
3
+ Version: 1.4.2.dev2
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License-Expression: Apache-2.0
@@ -52,8 +52,9 @@ def _fill(msg, desc: Descriptor, rand: Random) -> None:
52
52
  if hasattr(field, "is_repeated"):
53
53
  is_repeated = field.is_repeated # type: ignore
54
54
  else:
55
- is_repeated = field.label == FieldDescriptor.LABEL_REPEATED
55
+ is_repeated = field.label == FieldDescriptor.LABEL_REPEATED # type: ignore[attr-defined]
56
56
  if is_message:
57
+ assert field.message_type is not None
57
58
  msg_field = getattr(msg, field.name)
58
59
  if is_repeated:
59
60
  num = rand.randint(0, 2)
@@ -64,6 +65,7 @@ def _fill(msg, desc: Descriptor, rand: Random) -> None:
64
65
  _fill(msg_field, field.message_type, rand)
65
66
  else:
66
67
  if field.type == FieldDescriptor.TYPE_ENUM:
68
+ assert field.enum_type is not None
67
69
  enum_values = [x.number for x in field.enum_type.values]
68
70
  generator = lambda rand: rand.choice(enum_values) # noqa: E731
69
71
 
@@ -122,6 +122,15 @@ async def fetch_command_router_access(server_client, task_id: str) -> api_pb2.Ta
122
122
  )
123
123
 
124
124
 
125
+ async def fetch_command_router_access_v2(
126
+ server_client, sandbox_id: str
127
+ ) -> api_pb2.SandboxGetCommandRouterAccessResponse:
128
+ """Fetch direct command router access info from Modal server for a V2 sandbox."""
129
+ return await server_client.stub.SandboxGetCommandRouterAccess(
130
+ api_pb2.SandboxGetCommandRouterAccessRequest(sandbox_id=sandbox_id),
131
+ )
132
+
133
+
125
134
  def _finalize_channel(loop, channel):
126
135
  if not loop.is_closed():
127
136
  # only run if loop has not shut down
@@ -139,27 +148,19 @@ class TaskCommandRouterClient:
139
148
  """
140
149
 
141
150
  @classmethod
142
- async def try_init(
151
+ async def _connect(
143
152
  cls,
144
153
  server_client,
145
154
  task_id: str,
146
- ) -> Optional["TaskCommandRouterClient"]:
147
- """Attempt to initialize a TaskCommandRouterClient by fetching direct access.
148
-
149
- Returns None if command router access is not enabled (FAILED_PRECONDITION).
150
- """
151
- try:
152
- resp = await fetch_command_router_access(server_client, task_id)
153
- except ConflictError:
154
- logger.debug(f"Command router access is not enabled for task {task_id}")
155
- return None
156
-
157
- logger.debug(f"Using command router access for task {task_id}")
158
-
159
- # Build and connect a channel to the task command router now that we have access info.
160
- o = urllib.parse.urlparse(resp.url)
155
+ url: str,
156
+ jwt: str,
157
+ *,
158
+ sandbox_id: Optional[str] = None,
159
+ ) -> "TaskCommandRouterClient":
160
+ """Build a connected client from a jwt and url."""
161
+ o = urllib.parse.urlparse(url)
161
162
  if o.scheme != "https":
162
- raise ValueError(f"Task router URL must be https, got: {resp.url}")
163
+ raise ValueError(f"Task router URL must be https, got: {url}")
163
164
 
164
165
  host, _, port_str = o.netloc.partition(":")
165
166
  port = int(port_str) if port_str else 443
@@ -189,7 +190,38 @@ class TaskCommandRouterClient:
189
190
  loop = asyncio.get_running_loop()
190
191
  jwt_refresh_lock = asyncio.Lock()
191
192
 
192
- return cls(server_client, task_id, resp.url, resp.jwt, channel, loop, jwt_refresh_lock)
193
+ return cls(server_client, task_id, url, jwt, channel, loop, jwt_refresh_lock, sandbox_id=sandbox_id)
194
+
195
+ @classmethod
196
+ async def try_init(
197
+ cls,
198
+ server_client,
199
+ task_id: str,
200
+ ) -> Optional["TaskCommandRouterClient"]:
201
+ """Attempt to initialize a TaskCommandRouterClient by fetching direct access.
202
+
203
+ Returns None if command router access is not enabled (FAILED_PRECONDITION).
204
+ """
205
+ try:
206
+ resp = await fetch_command_router_access(server_client, task_id)
207
+ except ConflictError:
208
+ logger.debug(f"Command router access is not enabled for task {task_id}")
209
+ return None
210
+
211
+ logger.debug(f"Using command router access for task {task_id}")
212
+ return await cls._connect(server_client, task_id, resp.url, resp.jwt)
213
+
214
+ @classmethod
215
+ async def init_v2(
216
+ cls,
217
+ server_client,
218
+ sandbox_id: str,
219
+ task_id: str,
220
+ ) -> "TaskCommandRouterClient":
221
+ """Initialize a TaskCommandRouterClient for a V2 sandbox."""
222
+ resp = await fetch_command_router_access_v2(server_client, sandbox_id)
223
+ logger.debug(f"Using command router access for sandbox {sandbox_id}")
224
+ return await cls._connect(server_client, task_id, resp.url, resp.jwt, sandbox_id=sandbox_id)
193
225
 
194
226
  def __init__(
195
227
  self,
@@ -201,6 +233,7 @@ class TaskCommandRouterClient:
201
233
  loop: asyncio.AbstractEventLoop,
202
234
  jwt_refresh_lock: asyncio.Lock,
203
235
  *,
236
+ sandbox_id: Optional[str] = None,
204
237
  stream_stdio_retry_delay_secs: float = 0.01,
205
238
  stream_stdio_retry_delay_factor: float = 2,
206
239
  stream_stdio_max_retries: int = 10,
@@ -213,6 +246,7 @@ class TaskCommandRouterClient:
213
246
  # Attach bearer token on all requests to the worker-side router service.
214
247
  self._server_client = server_client
215
248
  self._task_id = task_id
249
+ self._sandbox_id = sandbox_id
216
250
  self._server_url = server_url
217
251
  self._jwt = jwt
218
252
  self._channel = channel
@@ -237,6 +271,10 @@ class TaskCommandRouterClient:
237
271
 
238
272
  self._stub = TaskCommandRouterStub(self._channel)
239
273
 
274
+ @property
275
+ def _is_v2_sandbox(self) -> bool:
276
+ return self._sandbox_id is not None
277
+
240
278
  def _get_metadata(self):
241
279
  return {"authorization": f"Bearer {self._jwt}"}
242
280
 
@@ -452,14 +490,21 @@ class TaskCommandRouterClient:
452
490
  )
453
491
  return
454
492
 
455
- logger.debug(f"Refreshing JWT for exec with task ID {self._task_id}")
456
- resp = await fetch_command_router_access(self._server_client, self._task_id)
457
- logger.debug(f"Finished refreshing JWT for exec with task ID {self._task_id}")
493
+ if self._is_v2_sandbox:
494
+ logger.debug(f"Refreshing JWT for exec with sandbox ID {self._sandbox_id}")
495
+ v2_resp = await fetch_command_router_access_v2(self._server_client, self._sandbox_id)
496
+ logger.debug(f"Finished refreshing JWT for exec with sandbox ID {self._sandbox_id}")
497
+ jwt, url = v2_resp.jwt, v2_resp.url
498
+ else:
499
+ logger.debug(f"Refreshing JWT for exec with task ID {self._task_id}")
500
+ v1_resp = await fetch_command_router_access(self._server_client, self._task_id)
501
+ logger.debug(f"Finished refreshing JWT for exec with task ID {self._task_id}")
502
+ jwt, url = v1_resp.jwt, v1_resp.url
458
503
 
459
504
  # Ensure the server URL remains stable for the lifetime of this client.
460
- assert resp.url == self._server_url, "Task router URL changed during session"
461
- self._jwt = resp.jwt
462
- self._jwt_exp = _parse_jwt_expiration(resp.jwt)
505
+ assert url == self._server_url, "Task router URL changed during session"
506
+ self._jwt = jwt
507
+ self._jwt_exp = _parse_jwt_expiration(jwt)
463
508
 
464
509
  async def _call_with_auth_retry(self, func, *args, **kwargs):
465
510
  try:
@@ -1290,12 +1290,12 @@ class _App:
1290
1290
 
1291
1291
  ```python
1292
1292
  app_a = modal.App("a")
1293
- @app.function()
1293
+ @app_a.function()
1294
1294
  def foo():
1295
1295
  ...
1296
1296
 
1297
1297
  app_b = modal.App("b")
1298
- @app.function()
1298
+ @app_b.function()
1299
1299
  def bar():
1300
1300
  ...
1301
1301
 
@@ -618,12 +618,12 @@ class _App:
618
618
 
619
619
  ```python
620
620
  app_a = modal.App("a")
621
- @app.function()
621
+ @app_a.function()
622
622
  def foo():
623
623
  ...
624
624
 
625
625
  app_b = modal.App("b")
626
- @app.function()
626
+ @app_b.function()
627
627
  def bar():
628
628
  ...
629
629
 
@@ -1334,12 +1334,12 @@ class App:
1334
1334
 
1335
1335
  ```python
1336
1336
  app_a = modal.App("a")
1337
- @app.function()
1337
+ @app_a.function()
1338
1338
  def foo():
1339
1339
  ...
1340
1340
 
1341
1341
  app_b = modal.App("b")
1342
- @app.function()
1342
+ @app_b.function()
1343
1343
  def bar():
1344
1344
  ...
1345
1345
 
@@ -1,8 +1,12 @@
1
1
  # Copyright Modal Labs 2022
2
2
  import re
3
+ import sys
4
+ import time
5
+ import warnings
3
6
  from datetime import datetime, timedelta, timezone
4
- from typing import Optional, Union
7
+ from typing import Optional, Union, get_args
5
8
 
9
+ import click
6
10
  import rich
7
11
  import typer
8
12
  from click import UsageError
@@ -11,10 +15,13 @@ from rich.text import Text
11
15
  from typer import Argument
12
16
 
13
17
  from modal._object import _get_environment_name
18
+ from modal._traceback import print_server_warnings
14
19
  from modal._utils.async_utils import synchronizer
15
20
  from modal._utils.browser_utils import open_url_and_display
16
21
  from modal.client import _Client
17
22
  from modal.environments import ensure_env
23
+ from modal.output import OutputManager
24
+ from modal.runner import DEPLOYMENT_STRATEGY_TYPE, _stop_and_wait_for_containers
18
25
  from modal_proto import api_pb2
19
26
 
20
27
  from .._logs import _FETCH_LIMIT, _MAX_FETCH_RANGE, LogsFilters
@@ -464,3 +471,62 @@ async def dashboard(
464
471
 
465
472
  url = f"https://modal.com/id/{app_id}"
466
473
  open_url_and_display(url, "App dashboard")
474
+
475
+
476
+ @app_cli.command("rollover", no_args_is_help=True, context_settings={"ignore_unknown_options": True})
477
+ @synchronizer.create_blocking
478
+ async def rollover(
479
+ app_identifier: str = APP_IDENTIFIER,
480
+ *,
481
+ strategy: str = typer.Option(
482
+ "rolling",
483
+ help="Strategy for rollover",
484
+ click_type=click.Choice(get_args(DEPLOYMENT_STRATEGY_TYPE)),
485
+ ),
486
+ env: Optional[str] = ENV_OPTION,
487
+ ):
488
+ """Rollover an App.
489
+
490
+ A rollover replaces existing containers with fresh ones built from the same
491
+ App version — useful for refreshing containers without changing your code.
492
+ The rollover appears as a new entry in the App's deployment history.
493
+
494
+ **Examples:**
495
+
496
+ Rollover an App using a rolling deployment. Running containers are now considered
497
+ outdated and new containers will replace them.
498
+
499
+ ```
500
+ modal app rollover my-app
501
+ ```
502
+
503
+ Rollover an App by termatining all running containers. Inputs on the queue will
504
+ start new containers.
505
+
506
+ ```
507
+ modal app rollover my-app --strategy recreate
508
+ ```
509
+ """
510
+ env = ensure_env(env)
511
+ output_mgr = OutputManager.get()
512
+ output_mgr.print(f"🔨 Starting app rollover with {strategy} strategy")
513
+ t0 = time.monotonic()
514
+
515
+ client = await _Client.from_env()
516
+ app_id = await get_app_id.aio(app_identifier, env, client)
517
+
518
+ req = api_pb2.AppRolloverRequest(app_id=app_id)
519
+ response = await client.stub.AppRollover(req)
520
+ print_server_warnings(response.server_warnings)
521
+
522
+ if strategy == "recreate":
523
+ try:
524
+ await _stop_and_wait_for_containers(client, app_id, response.deployed_at, env)
525
+ except Exception as exc:
526
+ warnings.warn(f"App updated successfully, but containers did not all terminate. {exc}", UserWarning)
527
+ output_mgr.print(f"\nView Deployment: [magenta]{response.url}[/magenta]")
528
+ sys.exit(1)
529
+
530
+ duration = time.monotonic() - t0
531
+ output_mgr.step_completed(f"Rollover completed in {duration:.3f}s with {strategy} strategy! 🎉")
532
+ output_mgr.print(f"\nView Deployment: [magenta]{response.url}[/magenta]")
@@ -40,8 +40,11 @@ class ImportRef:
40
40
  # app [+ function/entrypoint on that app]
41
41
  object_path: str = dataclasses.field(default="")
42
42
 
43
+ # modal command that was invoked, so that we can provide helpful error messages
44
+ command: str = dataclasses.field(default="")
43
45
 
44
- def parse_import_ref(object_ref: str, use_module_mode: bool = False) -> ImportRef:
46
+
47
+ def parse_import_ref(object_ref: str, use_module_mode: bool = False, command: str = "") -> ImportRef:
45
48
  if object_ref.find("::") > 1:
46
49
  file_or_module, object_path = object_ref.split("::", 1)
47
50
  elif object_ref.find(":") > 1:
@@ -49,7 +52,7 @@ def parse_import_ref(object_ref: str, use_module_mode: bool = False) -> ImportRe
49
52
  else:
50
53
  file_or_module, object_path = object_ref, ""
51
54
 
52
- return ImportRef(file_or_module, use_module_mode, object_path)
55
+ return ImportRef(file_or_module, use_module_mode, object_path, command)
53
56
 
54
57
 
55
58
  DEFAULT_APP_NAME = "app"
@@ -94,6 +97,22 @@ def import_file_or_module(import_ref: ImportRef, base_cmd: str = ""):
94
97
  assert spec.loader
95
98
  spec.loader.exec_module(module)
96
99
  except Exception as exc:
100
+ if isinstance(exc, ImportError) and "attempted relative import with no known parent package" in str(exc):
101
+ if import_ref.file_or_module and import_ref.command and not import_ref.use_module_mode:
102
+ file_path = Path(import_ref.file_or_module)
103
+ suggested_module_path = ".".join(file_path.parts).removesuffix(".py").lstrip(".")
104
+ suffix = f"::{import_ref.object_path}" if import_ref.object_path else ""
105
+ new_message = (
106
+ "The source file contains relative imports and is therefore written as "
107
+ "part of a Python package, but Modal was invoked in script mode "
108
+ f"(`{import_ref.command} {import_ref.file_or_module}{suffix}`). "
109
+ "Try invoking Modal in module mode instead, i.e. "
110
+ f"`{import_ref.command} -m {suggested_module_path}{suffix}`, "
111
+ "assuming that your path starts at the root of the package."
112
+ )
113
+ new_exc = InvalidError(new_message)
114
+ new_exc.__traceback__ = exc.__traceback__
115
+ raise _CliUserExecutionError(str(full_path)) from new_exc
97
116
  raise _CliUserExecutionError(str(full_path)) from exc
98
117
 
99
118
  return module
@@ -407,7 +407,7 @@ class RunGroup(click.Group):
407
407
  ctx.ensure_object(dict)
408
408
  ctx.obj["env"] = ensure_env(ctx.params["env"])
409
409
 
410
- import_ref = parse_import_ref(func_ref, use_module_mode=ctx.params["m"])
410
+ import_ref = parse_import_ref(func_ref, use_module_mode=ctx.params["m"], command="modal run")
411
411
  runnable, all_usable_commands = import_and_filter(
412
412
  import_ref, base_cmd="modal run", accept_local_entrypoint=True, accept_webhook=False
413
413
  )
@@ -517,7 +517,7 @@ def deploy(
517
517
  # this ensures that lookups without environment specification use the same env as specified
518
518
  env = ensure_env(env)
519
519
 
520
- import_ref = parse_import_ref(app_ref, use_module_mode=use_module_mode)
520
+ import_ref = parse_import_ref(app_ref, use_module_mode=use_module_mode, command="modal deploy")
521
521
 
522
522
  OutputManager.get().set_timestamps(timestamps)
523
523
  app = import_app_from_ref(import_ref, base_cmd="modal deploy")
@@ -568,7 +568,7 @@ def serve(
568
568
 
569
569
  """
570
570
  env = ensure_env(env)
571
- import_ref = parse_import_ref(app_ref, use_module_mode=use_module_mode)
571
+ import_ref = parse_import_ref(app_ref, use_module_mode=use_module_mode, command="modal serve")
572
572
 
573
573
  OutputManager.get().set_timestamps(timestamps)
574
574
  app = import_app_from_ref(import_ref, base_cmd="modal serve")
@@ -140,7 +140,7 @@ def _start_shell_in_running_container(ref: str, cmd: str, pty: bool) -> None:
140
140
 
141
141
 
142
142
  def _function_spec_from_ref(ref: str, use_module_mode: bool) -> _FunctionSpec:
143
- import_ref = parse_import_ref(ref, use_module_mode=use_module_mode)
143
+ import_ref = parse_import_ref(ref, use_module_mode=use_module_mode, command="modal shell")
144
144
  runnable, all_usable_commands = import_and_filter(
145
145
  import_ref,
146
146
  base_cmd="modal shell",
@@ -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.2.dev0",
38
+ version: str = "1.4.2.dev2",
39
39
  ):
40
40
  """mdmd:hidden
41
41
  The Modal client object is not intended to be instantiated directly by users.
@@ -171,7 +171,7 @@ class Client:
171
171
  server_url: str,
172
172
  client_type: int,
173
173
  credentials: typing.Optional[tuple[str, str]],
174
- version: str = "1.4.2.dev0",
174
+ version: str = "1.4.2.dev2",
175
175
  ):
176
176
  """mdmd:hidden
177
177
  The Modal client object is not intended to be instantiated directly by users.
@@ -136,12 +136,13 @@ def _agent_environment() -> Optional[str]:
136
136
  # Tool-specific environment variables
137
137
  _TOOL_SPECIFIC_ENV_VARS: list[tuple[str, str]] = [
138
138
  ("CLAUDECODE", "claude-code"),
139
+ ("CODEX_THREAD_ID", "codex"),
139
140
  ("GEMINI_CLI", "gemini-cli"),
140
141
  ("CURSOR_AGENT", "cursor"),
141
142
  ("CLINE_ACTIVE", "cline"),
142
143
  ("AUGMENT_AGENT", "augment"),
143
144
  ("OPENCODE_CLIENT", "opencode"),
144
- ("GOOSE_TERMINAL", "goose"),
145
+ ("GOOSE_TERMINAL", "goose"), # honk
145
146
  ("TRAE_AI_SHELL_ID", "trae"),
146
147
  ]
147
148
  for env_var, agent_name in _TOOL_SPECIFIC_ENV_VARS:
@@ -348,7 +348,7 @@ class Function(
348
348
 
349
349
  _call_generator: ___call_generator_spec
350
350
 
351
- class __remote_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER]):
351
+ class __remote_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER]):
352
352
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> ReturnType_INNER:
353
353
  """Calls the function remotely, executing it with the given arguments and returning the execution's result."""
354
354
  ...
@@ -357,7 +357,7 @@ class Function(
357
357
  """Calls the function remotely, executing it with the given arguments and returning the execution's result."""
358
358
  ...
359
359
 
360
- remote: __remote_spec[modal._functions.ReturnType, modal._functions.P]
360
+ remote: __remote_spec[modal._functions.P, modal._functions.ReturnType]
361
361
 
362
362
  class __remote_gen_spec(typing_extensions.Protocol):
363
363
  def __call__(self, /, *args, **kwargs) -> typing.Generator[typing.Any, None, None]:
@@ -384,7 +384,7 @@ class Function(
384
384
  """
385
385
  ...
386
386
 
387
- class ___experimental_spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER]):
387
+ class ___experimental_spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER]):
388
388
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
389
389
  """[Experimental] Calls the function with the given arguments, without waiting for the results.
390
390
 
@@ -407,7 +407,7 @@ class Function(
407
407
  """
408
408
  ...
409
409
 
410
- _experimental_spawn: ___experimental_spawn_spec[modal._functions.ReturnType, modal._functions.P]
410
+ _experimental_spawn: ___experimental_spawn_spec[modal._functions.P, modal._functions.ReturnType]
411
411
 
412
412
  class ___spawn_map_inner_spec(typing_extensions.Protocol[P_INNER]):
413
413
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> None: ...
@@ -415,7 +415,7 @@ class Function(
415
415
 
416
416
  _spawn_map_inner: ___spawn_map_inner_spec[modal._functions.P]
417
417
 
418
- class __spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER]):
418
+ class __spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER]):
419
419
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
420
420
  """Calls the function with the given arguments, without waiting for the results.
421
421
 
@@ -436,7 +436,7 @@ class Function(
436
436
  """
437
437
  ...
438
438
 
439
- spawn: __spawn_spec[modal._functions.ReturnType, modal._functions.P]
439
+ spawn: __spawn_spec[modal._functions.P, modal._functions.ReturnType]
440
440
 
441
441
  def get_raw_f(self) -> collections.abc.Callable[..., typing.Any]:
442
442
  """Return the inner Python object wrapped by this Modal Function."""
@@ -1187,9 +1187,13 @@ class _Sandbox(_Object, type_prefix="sb"):
1187
1187
 
1188
1188
  async def _get_command_router_client(self, task_id: str) -> Optional[TaskCommandRouterClient]:
1189
1189
  if self._command_router_client is None:
1190
- # Attempt to initialize a router client. Returns None if the new exec path not enabled
1191
- # for this sandbox.
1192
- self._command_router_client = await TaskCommandRouterClient.try_init(self._client, task_id)
1190
+ if self._is_v2:
1191
+ self._command_router_client = await TaskCommandRouterClient.init_v2(
1192
+ self._client, self.object_id, task_id
1193
+ )
1194
+ else:
1195
+ # Returns None if command router access is not enabled for this sandbox.
1196
+ self._command_router_client = await TaskCommandRouterClient.try_init(self._client, task_id)
1193
1197
  return self._command_router_client
1194
1198
 
1195
1199
  @property
@@ -1267,7 +1271,6 @@ class _Sandbox(_Object, type_prefix="sb"):
1267
1271
  print(line)
1268
1272
  ```
1269
1273
  """
1270
- self._ensure_v1("exec")
1271
1274
  if pty_info is not None or _pty_info is not None:
1272
1275
  deprecation_warning(
1273
1276
  (2025, 9, 12),
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.4.2.dev0
3
+ Version: 1.4.2.dev2
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License-Expression: Apache-2.0
@@ -51,6 +51,10 @@ class ModalClientBase(abc.ABC):
51
51
  async def AppGetLayout(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.AppGetLayoutRequest, modal_proto.api_pb2.AppGetLayoutResponse]') -> None:
52
52
  pass
53
53
 
54
+ @abc.abstractmethod
55
+ async def AppGetLifecycle(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.AppGetLifecycleRequest, modal_proto.api_pb2.AppGetLifecycleResponse]') -> None:
56
+ pass
57
+
54
58
  @abc.abstractmethod
55
59
  async def AppGetLogs(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.AppGetLogsRequest, modal_proto.api_pb2.TaskLogsBatch]') -> None:
56
60
  pass
@@ -87,6 +91,10 @@ class ModalClientBase(abc.ABC):
87
91
  async def AppRollback(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.AppRollbackRequest, google.protobuf.empty_pb2.Empty]') -> None:
88
92
  pass
89
93
 
94
+ @abc.abstractmethod
95
+ async def AppRollover(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.AppRolloverRequest, modal_proto.api_pb2.AppRolloverResponse]') -> None:
96
+ pass
97
+
90
98
  @abc.abstractmethod
91
99
  async def AppSetObjects(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.AppSetObjectsRequest, google.protobuf.empty_pb2.Empty]') -> None:
92
100
  pass
@@ -675,6 +683,10 @@ class ModalClientBase(abc.ABC):
675
683
  async def TaskResult(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.TaskResultRequest, google.protobuf.empty_pb2.Empty]') -> None:
676
684
  pass
677
685
 
686
+ @abc.abstractmethod
687
+ async def TemplateList(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.TemplateListRequest, modal_proto.api_pb2.TemplateListResponse]') -> None:
688
+ pass
689
+
678
690
  @abc.abstractmethod
679
691
  async def TokenFlowCreate(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.TokenFlowCreateRequest, modal_proto.api_pb2.TokenFlowCreateResponse]') -> None:
680
692
  pass
@@ -829,6 +841,12 @@ class ModalClientBase(abc.ABC):
829
841
  modal_proto.api_pb2.AppGetLayoutRequest,
830
842
  modal_proto.api_pb2.AppGetLayoutResponse,
831
843
  ),
844
+ '/modal.client.ModalClient/AppGetLifecycle': grpclib.const.Handler(
845
+ self.AppGetLifecycle,
846
+ grpclib.const.Cardinality.UNARY_UNARY,
847
+ modal_proto.api_pb2.AppGetLifecycleRequest,
848
+ modal_proto.api_pb2.AppGetLifecycleResponse,
849
+ ),
832
850
  '/modal.client.ModalClient/AppGetLogs': grpclib.const.Handler(
833
851
  self.AppGetLogs,
834
852
  grpclib.const.Cardinality.UNARY_STREAM,
@@ -883,6 +901,12 @@ class ModalClientBase(abc.ABC):
883
901
  modal_proto.api_pb2.AppRollbackRequest,
884
902
  google.protobuf.empty_pb2.Empty,
885
903
  ),
904
+ '/modal.client.ModalClient/AppRollover': grpclib.const.Handler(
905
+ self.AppRollover,
906
+ grpclib.const.Cardinality.UNARY_UNARY,
907
+ modal_proto.api_pb2.AppRolloverRequest,
908
+ modal_proto.api_pb2.AppRolloverResponse,
909
+ ),
886
910
  '/modal.client.ModalClient/AppSetObjects': grpclib.const.Handler(
887
911
  self.AppSetObjects,
888
912
  grpclib.const.Cardinality.UNARY_UNARY,
@@ -1765,6 +1789,12 @@ class ModalClientBase(abc.ABC):
1765
1789
  modal_proto.api_pb2.TaskResultRequest,
1766
1790
  google.protobuf.empty_pb2.Empty,
1767
1791
  ),
1792
+ '/modal.client.ModalClient/TemplateList': grpclib.const.Handler(
1793
+ self.TemplateList,
1794
+ grpclib.const.Cardinality.UNARY_UNARY,
1795
+ modal_proto.api_pb2.TemplateListRequest,
1796
+ modal_proto.api_pb2.TemplateListResponse,
1797
+ ),
1768
1798
  '/modal.client.ModalClient/TokenFlowCreate': grpclib.const.Handler(
1769
1799
  self.TokenFlowCreate,
1770
1800
  grpclib.const.Cardinality.UNARY_UNARY,
@@ -1975,6 +2005,12 @@ class ModalClientStub:
1975
2005
  modal_proto.api_pb2.AppGetLayoutRequest,
1976
2006
  modal_proto.api_pb2.AppGetLayoutResponse,
1977
2007
  )
2008
+ self.AppGetLifecycle = grpclib.client.UnaryUnaryMethod(
2009
+ channel,
2010
+ '/modal.client.ModalClient/AppGetLifecycle',
2011
+ modal_proto.api_pb2.AppGetLifecycleRequest,
2012
+ modal_proto.api_pb2.AppGetLifecycleResponse,
2013
+ )
1978
2014
  self.AppGetLogs = grpclib.client.UnaryStreamMethod(
1979
2015
  channel,
1980
2016
  '/modal.client.ModalClient/AppGetLogs',
@@ -2029,6 +2065,12 @@ class ModalClientStub:
2029
2065
  modal_proto.api_pb2.AppRollbackRequest,
2030
2066
  google.protobuf.empty_pb2.Empty,
2031
2067
  )
2068
+ self.AppRollover = grpclib.client.UnaryUnaryMethod(
2069
+ channel,
2070
+ '/modal.client.ModalClient/AppRollover',
2071
+ modal_proto.api_pb2.AppRolloverRequest,
2072
+ modal_proto.api_pb2.AppRolloverResponse,
2073
+ )
2032
2074
  self.AppSetObjects = grpclib.client.UnaryUnaryMethod(
2033
2075
  channel,
2034
2076
  '/modal.client.ModalClient/AppSetObjects',
@@ -2911,6 +2953,12 @@ class ModalClientStub:
2911
2953
  modal_proto.api_pb2.TaskResultRequest,
2912
2954
  google.protobuf.empty_pb2.Empty,
2913
2955
  )
2956
+ self.TemplateList = grpclib.client.UnaryUnaryMethod(
2957
+ channel,
2958
+ '/modal.client.ModalClient/TemplateList',
2959
+ modal_proto.api_pb2.TemplateListRequest,
2960
+ modal_proto.api_pb2.TemplateListResponse,
2961
+ )
2914
2962
  self.TokenFlowCreate = grpclib.client.UnaryUnaryMethod(
2915
2963
  channel,
2916
2964
  '/modal.client.ModalClient/TokenFlowCreate',