modAL 1.4.1__tar.gz → 1.4.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 (209) hide show
  1. {modal-1.4.1 → modal-1.4.1.dev0}/PKG-INFO +2 -2
  2. {modal-1.4.1 → modal-1.4.1.dev0}/modal/__init__.py +1 -2
  3. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_utils/sandbox_fs_utils.py +1 -13
  4. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_utils/task_command_router_client.py +1 -5
  5. {modal-1.4.1 → modal-1.4.1.dev0}/modal/cli/container.py +4 -25
  6. {modal-1.4.1 → modal-1.4.1.dev0}/modal/cli/import_refs.py +4 -13
  7. {modal-1.4.1 → modal-1.4.1.dev0}/modal/cli/run.py +2 -4
  8. {modal-1.4.1 → modal-1.4.1.dev0}/modal/cli/shell.py +1 -5
  9. {modal-1.4.1 → modal-1.4.1.dev0}/modal/client.py +1 -3
  10. {modal-1.4.1 → modal-1.4.1.dev0}/modal/client.pyi +10 -2
  11. {modal-1.4.1 → modal-1.4.1.dev0}/modal/config.py +0 -30
  12. {modal-1.4.1 → modal-1.4.1.dev0}/modal/dict.py +1 -2
  13. {modal-1.4.1 → modal-1.4.1.dev0}/modal/dict.pyi +2 -4
  14. {modal-1.4.1 → modal-1.4.1.dev0}/modal/functions.pyi +6 -6
  15. {modal-1.4.1 → modal-1.4.1.dev0}/modal/mount.py +5 -7
  16. {modal-1.4.1 → modal-1.4.1.dev0}/modal/queue.py +1 -2
  17. {modal-1.4.1 → modal-1.4.1.dev0}/modal/queue.pyi +2 -4
  18. {modal-1.4.1 → modal-1.4.1.dev0}/modal/sandbox.py +0 -108
  19. {modal-1.4.1 → modal-1.4.1.dev0}/modal/sandbox.pyi +0 -127
  20. {modal-1.4.1 → modal-1.4.1.dev0}/modal/secret.py +1 -2
  21. {modal-1.4.1 → modal-1.4.1.dev0}/modal/secret.pyi +2 -4
  22. {modal-1.4.1 → modal-1.4.1.dev0}/modal/volume.py +1 -2
  23. {modal-1.4.1 → modal-1.4.1.dev0}/modal/volume.pyi +2 -4
  24. {modal-1.4.1 → modal-1.4.1.dev0}/modal.egg-info/PKG-INFO +2 -2
  25. {modal-1.4.1 → modal-1.4.1.dev0}/modal.egg-info/requires.txt +1 -1
  26. {modal-1.4.1 → modal-1.4.1.dev0}/modal_proto/api_grpc.py +0 -16
  27. {modal-1.4.1 → modal-1.4.1.dev0}/modal_proto/api_pb2.py +1040 -1060
  28. {modal-1.4.1 → modal-1.4.1.dev0}/modal_proto/api_pb2.pyi +1 -39
  29. {modal-1.4.1 → modal-1.4.1.dev0}/modal_proto/api_pb2_grpc.py +0 -33
  30. {modal-1.4.1 → modal-1.4.1.dev0}/modal_proto/api_pb2_grpc.pyi +0 -10
  31. {modal-1.4.1 → modal-1.4.1.dev0}/modal_proto/modal_api_grpc.py +0 -1
  32. {modal-1.4.1 → modal-1.4.1.dev0}/modal_proto/task_command_router_pb2.py +30 -43
  33. {modal-1.4.1 → modal-1.4.1.dev0}/modal_proto/task_command_router_pb2.pyi +1 -21
  34. {modal-1.4.1 → modal-1.4.1.dev0}/modal_version/__init__.py +1 -1
  35. {modal-1.4.1 → modal-1.4.1.dev0}/pyproject.toml +2 -2
  36. {modal-1.4.1 → modal-1.4.1.dev0}/LICENSE +0 -0
  37. {modal-1.4.1 → modal-1.4.1.dev0}/README.md +0 -0
  38. {modal-1.4.1 → modal-1.4.1.dev0}/modal/__main__.py +0 -0
  39. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_billing.py +0 -0
  40. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_clustered_functions.py +0 -0
  41. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_clustered_functions.pyi +0 -0
  42. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_container_entrypoint.py +0 -0
  43. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_functions.py +0 -0
  44. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_grpc_client.py +0 -0
  45. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_ipython.py +0 -0
  46. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_load_context.py +0 -0
  47. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_location.py +0 -0
  48. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_logs.py +0 -0
  49. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_object.py +0 -0
  50. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_output/__init__.py +0 -0
  51. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_output/manager.py +0 -0
  52. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_output/pty.py +0 -0
  53. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_output/rich.py +0 -0
  54. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_output/status.py +0 -0
  55. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_partial_function.py +0 -0
  56. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_resolver.py +0 -0
  57. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_resources.py +0 -0
  58. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_runtime/__init__.py +0 -0
  59. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_runtime/asgi.py +0 -0
  60. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_runtime/container_io_manager.py +0 -0
  61. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_runtime/container_io_manager.pyi +0 -0
  62. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_runtime/execution_context.py +0 -0
  63. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_runtime/execution_context.pyi +0 -0
  64. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_runtime/gpu_memory_snapshot.py +0 -0
  65. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_runtime/telemetry.py +0 -0
  66. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_runtime/user_code_event_loop.py +0 -0
  67. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_runtime/user_code_imports.py +0 -0
  68. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_serialization.py +0 -0
  69. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_server.py +0 -0
  70. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_traceback.py +0 -0
  71. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_tunnel.py +0 -0
  72. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_tunnel.pyi +0 -0
  73. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_type_manager.py +0 -0
  74. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_utils/__init__.py +0 -0
  75. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_utils/app_utils.py +0 -0
  76. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_utils/async_utils.py +0 -0
  77. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_utils/auth_token_manager.py +0 -0
  78. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_utils/blob_utils.py +0 -0
  79. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_utils/browser_utils.py +0 -0
  80. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_utils/bytes_io_segment_payload.py +0 -0
  81. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_utils/deprecation.py +0 -0
  82. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_utils/docker_utils.py +0 -0
  83. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_utils/function_utils.py +0 -0
  84. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_utils/git_utils.py +0 -0
  85. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_utils/grpc_testing.py +0 -0
  86. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_utils/grpc_utils.py +0 -0
  87. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_utils/hash_utils.py +0 -0
  88. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_utils/http_utils.py +0 -0
  89. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_utils/jwt_utils.py +0 -0
  90. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_utils/logger.py +0 -0
  91. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_utils/mount_utils.py +0 -0
  92. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_utils/name_utils.py +0 -0
  93. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_utils/package_utils.py +0 -0
  94. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_utils/pattern_utils.py +0 -0
  95. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_utils/rand_pb_testing.py +0 -0
  96. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_utils/shell_utils.py +0 -0
  97. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_utils/time_utils.py +0 -0
  98. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_vendor/__init__.py +0 -0
  99. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_vendor/a2wsgi_wsgi.py +0 -0
  100. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_vendor/cloudpickle.py +0 -0
  101. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_vendor/tblib.py +0 -0
  102. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_vendor/version.py +0 -0
  103. {modal-1.4.1 → modal-1.4.1.dev0}/modal/_watcher.py +0 -0
  104. {modal-1.4.1 → modal-1.4.1.dev0}/modal/app.py +0 -0
  105. {modal-1.4.1 → modal-1.4.1.dev0}/modal/app.pyi +0 -0
  106. {modal-1.4.1 → modal-1.4.1.dev0}/modal/billing.py +0 -0
  107. {modal-1.4.1 → modal-1.4.1.dev0}/modal/builder/2023.12.312.txt +0 -0
  108. {modal-1.4.1 → modal-1.4.1.dev0}/modal/builder/2023.12.txt +0 -0
  109. {modal-1.4.1 → modal-1.4.1.dev0}/modal/builder/2024.04.txt +0 -0
  110. {modal-1.4.1 → modal-1.4.1.dev0}/modal/builder/2024.10.txt +0 -0
  111. {modal-1.4.1 → modal-1.4.1.dev0}/modal/builder/2025.06.txt +0 -0
  112. {modal-1.4.1 → modal-1.4.1.dev0}/modal/builder/PREVIEW.txt +0 -0
  113. {modal-1.4.1 → modal-1.4.1.dev0}/modal/builder/README.md +0 -0
  114. {modal-1.4.1 → modal-1.4.1.dev0}/modal/builder/base-images.json +0 -0
  115. {modal-1.4.1 → modal-1.4.1.dev0}/modal/call_graph.py +0 -0
  116. {modal-1.4.1 → modal-1.4.1.dev0}/modal/cli/__init__.py +0 -0
  117. {modal-1.4.1 → modal-1.4.1.dev0}/modal/cli/_download.py +0 -0
  118. {modal-1.4.1 → modal-1.4.1.dev0}/modal/cli/_traceback.py +0 -0
  119. {modal-1.4.1 → modal-1.4.1.dev0}/modal/cli/app.py +0 -0
  120. {modal-1.4.1 → modal-1.4.1.dev0}/modal/cli/billing.py +0 -0
  121. {modal-1.4.1 → modal-1.4.1.dev0}/modal/cli/changelog.py +0 -0
  122. {modal-1.4.1 → modal-1.4.1.dev0}/modal/cli/cluster.py +0 -0
  123. {modal-1.4.1 → modal-1.4.1.dev0}/modal/cli/config.py +0 -0
  124. {modal-1.4.1 → modal-1.4.1.dev0}/modal/cli/dashboard.py +0 -0
  125. {modal-1.4.1 → modal-1.4.1.dev0}/modal/cli/dict.py +0 -0
  126. {modal-1.4.1 → modal-1.4.1.dev0}/modal/cli/entry_point.py +0 -0
  127. {modal-1.4.1 → modal-1.4.1.dev0}/modal/cli/environment.py +0 -0
  128. {modal-1.4.1 → modal-1.4.1.dev0}/modal/cli/launch.py +0 -0
  129. {modal-1.4.1 → modal-1.4.1.dev0}/modal/cli/network_file_system.py +0 -0
  130. {modal-1.4.1 → modal-1.4.1.dev0}/modal/cli/profile.py +0 -0
  131. {modal-1.4.1 → modal-1.4.1.dev0}/modal/cli/programs/__init__.py +0 -0
  132. {modal-1.4.1 → modal-1.4.1.dev0}/modal/cli/programs/run_jupyter.py +0 -0
  133. {modal-1.4.1 → modal-1.4.1.dev0}/modal/cli/programs/vscode.py +0 -0
  134. {modal-1.4.1 → modal-1.4.1.dev0}/modal/cli/queues.py +0 -0
  135. {modal-1.4.1 → modal-1.4.1.dev0}/modal/cli/secret.py +0 -0
  136. {modal-1.4.1 → modal-1.4.1.dev0}/modal/cli/selector.py +0 -0
  137. {modal-1.4.1 → modal-1.4.1.dev0}/modal/cli/token.py +0 -0
  138. {modal-1.4.1 → modal-1.4.1.dev0}/modal/cli/utils.py +0 -0
  139. {modal-1.4.1 → modal-1.4.1.dev0}/modal/cli/volume.py +0 -0
  140. {modal-1.4.1 → modal-1.4.1.dev0}/modal/cloud_bucket_mount.py +0 -0
  141. {modal-1.4.1 → modal-1.4.1.dev0}/modal/cloud_bucket_mount.pyi +0 -0
  142. {modal-1.4.1 → modal-1.4.1.dev0}/modal/cls.py +0 -0
  143. {modal-1.4.1 → modal-1.4.1.dev0}/modal/cls.pyi +0 -0
  144. {modal-1.4.1 → modal-1.4.1.dev0}/modal/container_process.py +0 -0
  145. {modal-1.4.1 → modal-1.4.1.dev0}/modal/container_process.pyi +0 -0
  146. {modal-1.4.1 → modal-1.4.1.dev0}/modal/environments.py +0 -0
  147. {modal-1.4.1 → modal-1.4.1.dev0}/modal/environments.pyi +0 -0
  148. {modal-1.4.1 → modal-1.4.1.dev0}/modal/exception.py +0 -0
  149. {modal-1.4.1 → modal-1.4.1.dev0}/modal/experimental/__init__.py +0 -0
  150. {modal-1.4.1 → modal-1.4.1.dev0}/modal/experimental/flash.py +0 -0
  151. {modal-1.4.1 → modal-1.4.1.dev0}/modal/experimental/flash.pyi +0 -0
  152. {modal-1.4.1 → modal-1.4.1.dev0}/modal/experimental/ipython.py +0 -0
  153. {modal-1.4.1 → modal-1.4.1.dev0}/modal/file_io.py +0 -0
  154. {modal-1.4.1 → modal-1.4.1.dev0}/modal/file_io.pyi +0 -0
  155. {modal-1.4.1 → modal-1.4.1.dev0}/modal/file_pattern_matcher.py +0 -0
  156. {modal-1.4.1 → modal-1.4.1.dev0}/modal/functions.py +0 -0
  157. {modal-1.4.1 → modal-1.4.1.dev0}/modal/image.py +0 -0
  158. {modal-1.4.1 → modal-1.4.1.dev0}/modal/image.pyi +0 -0
  159. {modal-1.4.1 → modal-1.4.1.dev0}/modal/io_streams.py +0 -0
  160. {modal-1.4.1 → modal-1.4.1.dev0}/modal/io_streams.pyi +0 -0
  161. {modal-1.4.1 → modal-1.4.1.dev0}/modal/mount.pyi +0 -0
  162. {modal-1.4.1 → modal-1.4.1.dev0}/modal/network_file_system.py +0 -0
  163. {modal-1.4.1 → modal-1.4.1.dev0}/modal/network_file_system.pyi +0 -0
  164. {modal-1.4.1 → modal-1.4.1.dev0}/modal/object.py +0 -0
  165. {modal-1.4.1 → modal-1.4.1.dev0}/modal/object.pyi +0 -0
  166. {modal-1.4.1 → modal-1.4.1.dev0}/modal/output.py +0 -0
  167. {modal-1.4.1 → modal-1.4.1.dev0}/modal/parallel_map.py +0 -0
  168. {modal-1.4.1 → modal-1.4.1.dev0}/modal/parallel_map.pyi +0 -0
  169. {modal-1.4.1 → modal-1.4.1.dev0}/modal/partial_function.py +0 -0
  170. {modal-1.4.1 → modal-1.4.1.dev0}/modal/partial_function.pyi +0 -0
  171. {modal-1.4.1 → modal-1.4.1.dev0}/modal/proxy.py +0 -0
  172. {modal-1.4.1 → modal-1.4.1.dev0}/modal/proxy.pyi +0 -0
  173. {modal-1.4.1 → modal-1.4.1.dev0}/modal/py.typed +0 -0
  174. {modal-1.4.1 → modal-1.4.1.dev0}/modal/retries.py +0 -0
  175. {modal-1.4.1 → modal-1.4.1.dev0}/modal/runner.py +0 -0
  176. {modal-1.4.1 → modal-1.4.1.dev0}/modal/runner.pyi +0 -0
  177. {modal-1.4.1 → modal-1.4.1.dev0}/modal/running_app.py +0 -0
  178. {modal-1.4.1 → modal-1.4.1.dev0}/modal/sandbox_fs.py +0 -0
  179. {modal-1.4.1 → modal-1.4.1.dev0}/modal/sandbox_fs.pyi +0 -0
  180. {modal-1.4.1 → modal-1.4.1.dev0}/modal/schedule.py +0 -0
  181. {modal-1.4.1 → modal-1.4.1.dev0}/modal/scheduler_placement.py +0 -0
  182. {modal-1.4.1 → modal-1.4.1.dev0}/modal/server.py +0 -0
  183. {modal-1.4.1 → modal-1.4.1.dev0}/modal/server.pyi +0 -0
  184. {modal-1.4.1 → modal-1.4.1.dev0}/modal/serving.py +0 -0
  185. {modal-1.4.1 → modal-1.4.1.dev0}/modal/serving.pyi +0 -0
  186. {modal-1.4.1 → modal-1.4.1.dev0}/modal/snapshot.py +0 -0
  187. {modal-1.4.1 → modal-1.4.1.dev0}/modal/snapshot.pyi +0 -0
  188. {modal-1.4.1 → modal-1.4.1.dev0}/modal/stream_type.py +0 -0
  189. {modal-1.4.1 → modal-1.4.1.dev0}/modal/token_flow.py +0 -0
  190. {modal-1.4.1 → modal-1.4.1.dev0}/modal/token_flow.pyi +0 -0
  191. {modal-1.4.1 → modal-1.4.1.dev0}/modal.egg-info/SOURCES.txt +0 -0
  192. {modal-1.4.1 → modal-1.4.1.dev0}/modal.egg-info/dependency_links.txt +0 -0
  193. {modal-1.4.1 → modal-1.4.1.dev0}/modal.egg-info/entry_points.txt +0 -0
  194. {modal-1.4.1 → modal-1.4.1.dev0}/modal.egg-info/top_level.txt +0 -0
  195. {modal-1.4.1 → modal-1.4.1.dev0}/modal_docs/__init__.py +0 -0
  196. {modal-1.4.1 → modal-1.4.1.dev0}/modal_docs/gen_cli_docs.py +0 -0
  197. {modal-1.4.1 → modal-1.4.1.dev0}/modal_docs/gen_cli_docs_main.py +0 -0
  198. {modal-1.4.1 → modal-1.4.1.dev0}/modal_docs/gen_reference_docs.py +0 -0
  199. {modal-1.4.1 → modal-1.4.1.dev0}/modal_docs/gen_reference_docs_main.py +0 -0
  200. {modal-1.4.1 → modal-1.4.1.dev0}/modal_docs/mdmd/__init__.py +0 -0
  201. {modal-1.4.1 → modal-1.4.1.dev0}/modal_docs/mdmd/mdmd.py +0 -0
  202. {modal-1.4.1 → modal-1.4.1.dev0}/modal_docs/mdmd/signatures.py +0 -0
  203. {modal-1.4.1 → modal-1.4.1.dev0}/modal_proto/__init__.py +0 -0
  204. {modal-1.4.1 → modal-1.4.1.dev0}/modal_proto/py.typed +0 -0
  205. {modal-1.4.1 → modal-1.4.1.dev0}/modal_proto/task_command_router_grpc.py +0 -0
  206. {modal-1.4.1 → modal-1.4.1.dev0}/modal_proto/task_command_router_pb2_grpc.py +0 -0
  207. {modal-1.4.1 → modal-1.4.1.dev0}/modal_proto/task_command_router_pb2_grpc.pyi +0 -0
  208. {modal-1.4.1 → modal-1.4.1.dev0}/modal_version/__main__.py +0 -0
  209. {modal-1.4.1 → modal-1.4.1.dev0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.4.1
3
+ Version: 1.4.1.dev0
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License-Expression: Apache-2.0
@@ -23,7 +23,7 @@ Requires-Dist: grpclib<0.4.10,>=0.4.7; python_version < "3.14"
23
23
  Requires-Dist: grpclib<0.4.10,>=0.4.9; python_version >= "3.14"
24
24
  Requires-Dist: protobuf!=4.24.0,<7.0,>=3.19
25
25
  Requires-Dist: rich>=12.0.0
26
- Requires-Dist: synchronicity~=0.12.1
26
+ Requires-Dist: synchronicity~=0.11.1
27
27
  Requires-Dist: toml
28
28
  Requires-Dist: typer>=0.9
29
29
  Requires-Dist: types-certifi
@@ -38,7 +38,7 @@ try:
38
38
  from .proxy import Proxy
39
39
  from .queue import Queue
40
40
  from .retries import Retries
41
- from .sandbox import Probe, Sandbox
41
+ from .sandbox import Sandbox
42
42
  from .schedule import Cron, Period
43
43
  from .scheduler_placement import SchedulerPlacement
44
44
  from .secret import Secret
@@ -68,7 +68,6 @@ __all__ = [
68
68
  "Image",
69
69
  "NetworkFileSystem",
70
70
  "Period",
71
- "Probe",
72
71
  "Proxy",
73
72
  "Queue",
74
73
  "Retries",
@@ -28,7 +28,6 @@ _EXEC_SANDBOX_UNAVAILABLE_ERROR_TYPES = (NotFoundError, ServiceError, Connection
28
28
  class ErrorPayload:
29
29
  error_kind: str
30
30
  message: str
31
- detail: str = ""
32
31
 
33
32
 
34
33
  def _stderr_to_text(stderr: Union[str, bytes]) -> str:
@@ -52,18 +51,11 @@ def try_parse_error_payload(stderr: Union[str, bytes]) -> Optional[ErrorPayload]
52
51
  return None
53
52
  if not isinstance(message, str) or not message.strip():
54
53
  return None
55
- detail = payload.get("detail", "")
56
- if not isinstance(detail, str):
57
- detail = ""
58
- return ErrorPayload(error_kind=error_kind, message=message, detail=detail)
54
+ return ErrorPayload(error_kind=error_kind, message=message)
59
55
 
60
56
 
61
57
  def raise_read_file_error(returncode: int, stderr: Union[str, bytes], remote_path: str) -> NoReturn:
62
58
  if payload := try_parse_error_payload(stderr):
63
- logger.debug(
64
- f"sandbox-fs-tools read error: path={remote_path}, "
65
- f"error_kind={payload.error_kind}, message={payload.message}, detail={payload.detail}"
66
- )
67
59
  if payload.error_kind == "NotFound":
68
60
  raise SandboxFilesystemNotFoundError(f"{payload.message}: {remote_path}")
69
61
  if payload.error_kind == "IsDirectory":
@@ -114,10 +106,6 @@ def translate_exec_unexpected_error(operation: str, path: str, exc: Exception) -
114
106
 
115
107
  def raise_write_file_error(returncode: int, stderr: Union[str, bytes], remote_path: str) -> NoReturn:
116
108
  if payload := try_parse_error_payload(stderr):
117
- logger.debug(
118
- f"sandbox-fs-tools write error: path={remote_path}, "
119
- f"error_kind={payload.error_kind}, message={payload.message}, detail={payload.detail}"
120
- )
121
109
  if payload.error_kind == "NotDirectory" or payload.error_kind == "AlreadyExists":
122
110
  raise SandboxFilesystemNotADirectoryError(f"{payload.message}: {remote_path}")
123
111
  if payload.error_kind == "IsDirectory":
@@ -2,7 +2,6 @@
2
2
  import asyncio
3
3
  import base64
4
4
  import json
5
- import socket
6
5
  import ssl
7
6
  import time
8
7
  import urllib.parse
@@ -182,10 +181,7 @@ class TaskCommandRouterClient:
182
181
  closed_error_message="Unable to perform operation on a detached sandbox",
183
182
  )
184
183
 
185
- try:
186
- await _connect_channel(channel)
187
- except socket.gaierror as exc:
188
- raise ConnectionError(f"Could not resolve hostname '{host}': {exc}") from exc
184
+ await _connect_channel(channel)
189
185
  loop = asyncio.get_running_loop()
190
186
  jwt_refresh_lock = asyncio.Lock()
191
187
 
@@ -1,5 +1,4 @@
1
1
  # Copyright Modal Labs 2022
2
- import warnings
3
2
  from datetime import datetime, timezone
4
3
  from typing import Optional, Union
5
4
 
@@ -186,40 +185,20 @@ async def logs(
186
185
  task_info_resp = await client.stub.TaskGetInfo(api_pb2.TaskGetInfoRequest(task_id=task_id))
187
186
  app_id = task_info_resp.app_id
188
187
 
189
- if not task_info_resp.info.started_at:
190
- # Unlikely race or Modal backend issue, don't treat as a usage exception
191
- return
192
- container_started_dt = datetime.fromtimestamp(task_info_resp.info.started_at, timezone.utc)
193
-
194
188
  now = datetime.now(timezone.utc)
195
189
  if all_logs:
196
- since_dt = container_started_dt
190
+ since_dt = datetime.fromtimestamp(task_info_resp.info.started_at, timezone.utc)
197
191
  if task_info_resp.info.finished_at:
198
192
  until_dt = datetime.fromtimestamp(task_info_resp.info.finished_at, timezone.utc)
199
193
  else:
200
194
  until_dt = now
201
195
  else:
202
- since_dt = _parse_time_arg(since, default=container_started_dt)
203
- if task_info_resp.info.finished_at:
204
- default_until_dt = datetime.fromtimestamp(task_info_resp.info.finished_at, timezone.utc)
205
- else:
206
- default_until_dt = now
207
- until_dt = _parse_time_arg(until, default=default_until_dt)
196
+ since_dt = _parse_time_arg(since, default=now) if since else None
197
+ until_dt = _parse_time_arg(until, default=now) if until else None
208
198
 
209
- if since is not None and until is not None and since_dt >= until_dt:
210
- # User provided both --since and --until, but did so incorrectly
199
+ if since_dt is not None and until_dt is not None and since_dt >= until_dt:
211
200
  raise UsageError("--since must be before --until.")
212
201
 
213
- if since is not None and until is None and since_dt >= until_dt:
214
- # User provided only --since and it is after the container finished
215
- warnings.warn("--since time is after the Container finished, no logs to fetch.", UserWarning)
216
- return
217
-
218
- if until is not None and since is None and since_dt >= until_dt:
219
- # User provided only --until and it is before the Container started
220
- warnings.warn("--until time is before the Container started, no logs to fetch.", UserWarning)
221
- return
222
-
223
202
  if since_dt is not None:
224
203
  effective_until = until_dt or now
225
204
  if effective_until - since_dt > _MAX_FETCH_RANGE:
@@ -127,7 +127,6 @@ class AutoRunPriority:
127
127
 
128
128
  def list_cli_commands(
129
129
  module_members: dict[str, typing.Any],
130
- include_service_functions: bool = False,
131
130
  ) -> list[CLICommand]:
132
131
  """
133
132
  Extracts all runnables found either directly in the input module, or in any of the Apps listed in that module
@@ -150,8 +149,8 @@ def list_cli_commands(
150
149
  all_runnables[local_entrypoint].append(f"{app_name}.{name}")
151
150
  priorities[local_entrypoint] = AutoRunPriority.APP_LOCAL_ENTRYPOINT
152
151
  for name, function in app.registered_functions.items():
153
- if function.info.is_service_class() and not include_service_functions:
154
- continue # Skip class and server service functions for all commands except `modal shell`.
152
+ if function.info.is_service_class():
153
+ continue # Skip class and server service functions since they don't have associated cli commands
155
154
  all_runnables[function].append(f"{app_name}.{name}")
156
155
  priorities[function] = AutoRunPriority.APP_FUNCTION
157
156
  for cls_name, cls in app.registered_classes.items():
@@ -323,12 +322,7 @@ def _get_runnable_app(runnable: Runnable) -> App:
323
322
 
324
323
 
325
324
  def import_and_filter(
326
- import_ref: ImportRef,
327
- *,
328
- base_cmd: str,
329
- accept_local_entrypoint=True,
330
- accept_webhook=False,
331
- accept_service_functions=False,
325
+ import_ref: ImportRef, *, base_cmd: str, accept_local_entrypoint=True, accept_webhook=False
332
326
  ) -> tuple[Optional[Runnable], list[CLICommand]]:
333
327
  """Takes a function ref string and returns a single determined "runnable" to use, and a list of all available
334
328
  runnables.
@@ -345,10 +339,7 @@ def import_and_filter(
345
339
  """
346
340
  # all commands:
347
341
  module = import_file_or_module(import_ref, base_cmd)
348
- cli_commands = list_cli_commands(
349
- dict(inspect.getmembers(module)),
350
- include_service_functions=accept_service_functions,
351
- )
342
+ cli_commands = list_cli_commands(dict(inspect.getmembers(module)))
352
343
 
353
344
  # all commands that satisfy local entrypoint/accept webhook limitations AND object path prefix
354
345
 
@@ -7,7 +7,7 @@ import sys
7
7
  import time
8
8
  import typing
9
9
  from dataclasses import dataclass
10
- from typing import Any, Callable, Optional, get_args
10
+ from typing import Any, Callable, Optional
11
11
 
12
12
  import click
13
13
  import typer
@@ -504,9 +504,7 @@ def deploy(
504
504
  False, "-m", help="Interpret argument as a Python module path instead of a file/script path"
505
505
  ),
506
506
  timestamps: bool = typer.Option(False, "--timestamps", help="Show timestamps for each log line."),
507
- strategy: str = typer.Option(
508
- "rolling", help="Deployment strategy", click_type=click.Choice(get_args(DEPLOYMENT_STRATEGY_TYPE))
509
- ),
507
+ strategy: DEPLOYMENT_STRATEGY_TYPE = typer.Option("rolling", help="Deployment strategy"),
510
508
  ):
511
509
  """Deploy a Modal application.
512
510
 
@@ -142,11 +142,7 @@ def _start_shell_in_running_container(ref: str, cmd: str, pty: bool) -> None:
142
142
  def _function_spec_from_ref(ref: str, use_module_mode: bool) -> _FunctionSpec:
143
143
  import_ref = parse_import_ref(ref, use_module_mode=use_module_mode)
144
144
  runnable, all_usable_commands = import_and_filter(
145
- import_ref,
146
- base_cmd="modal shell",
147
- accept_local_entrypoint=False,
148
- accept_webhook=True,
149
- accept_service_functions=True,
145
+ import_ref, base_cmd="modal shell", accept_local_entrypoint=False, accept_webhook=True
150
146
  )
151
147
  if not runnable:
152
148
  help_header = (
@@ -22,7 +22,7 @@ from ._utils import async_utils
22
22
  from ._utils.async_utils import TaskContext, synchronize_api
23
23
  from ._utils.auth_token_manager import _AuthTokenManager
24
24
  from ._utils.grpc_utils import ConnectionManager
25
- from .config import _agent_environment, _check_config, _is_remote, config, logger
25
+ from .config import _check_config, _is_remote, config, logger
26
26
  from .exception import AuthError, ClientClosed
27
27
 
28
28
  HEARTBEAT_INTERVAL: float = config.get("heartbeat_interval")
@@ -56,8 +56,6 @@ def _get_metadata(client_type: int, credentials: Optional[tuple[str, str]], vers
56
56
  "x-modal-token-secret": token_secret,
57
57
  }
58
58
  )
59
- if agent_env := _agent_environment():
60
- metadata["x-modal-agent-harness"] = urllib.parse.quote(agent_env)
61
59
  return metadata
62
60
 
63
61
 
@@ -31,7 +31,11 @@ class _Client:
31
31
  client_type: int
32
32
 
33
33
  def __init__(
34
- self, server_url: str, client_type: int, credentials: typing.Optional[tuple[str, str]], version: str = "1.4.1"
34
+ self,
35
+ server_url: str,
36
+ client_type: int,
37
+ credentials: typing.Optional[tuple[str, str]],
38
+ version: str = "1.4.1.dev0",
35
39
  ):
36
40
  """mdmd:hidden
37
41
  The Modal client object is not intended to be instantiated directly by users.
@@ -163,7 +167,11 @@ class Client:
163
167
  client_type: int
164
168
 
165
169
  def __init__(
166
- self, server_url: str, client_type: int, credentials: typing.Optional[tuple[str, str]], version: str = "1.4.1"
170
+ self,
171
+ server_url: str,
172
+ client_type: int,
173
+ credentials: typing.Optional[tuple[str, str]],
174
+ version: str = "1.4.1.dev0",
167
175
  ):
168
176
  """mdmd:hidden
169
177
  The Modal client object is not intended to be instantiated directly by users.
@@ -121,36 +121,6 @@ def _is_remote() -> bool:
121
121
  return os.environ.get("MODAL_IS_REMOTE") == "1"
122
122
 
123
123
 
124
- def _agent_environment() -> Optional[str]:
125
- """Detect if the current process is running inside an AI agent harness.
126
-
127
- Returns the agent name if detected, or None otherwise.
128
-
129
- Checks the emerging `AGENT` standard variable first, then falls back to
130
- tool-specific environment variables used by known agent harnesses.
131
- """
132
- # Emerging standard: AGENT=<name>
133
- if agent := os.environ.get("AGENT"):
134
- return agent
135
-
136
- # Tool-specific environment variables
137
- _TOOL_SPECIFIC_ENV_VARS: list[tuple[str, str]] = [
138
- ("CLAUDECODE", "claude-code"),
139
- ("GEMINI_CLI", "gemini-cli"),
140
- ("CURSOR_AGENT", "cursor"),
141
- ("CLINE_ACTIVE", "cline"),
142
- ("AUGMENT_AGENT", "augment"),
143
- ("OPENCODE_CLIENT", "opencode"),
144
- ("GOOSE_TERMINAL", "goose"),
145
- ("TRAE_AI_SHELL_ID", "trae"),
146
- ]
147
- for env_var, agent_name in _TOOL_SPECIFIC_ENV_VARS:
148
- if os.environ.get(env_var):
149
- return agent_name
150
-
151
- return None
152
-
153
-
154
124
  def _read_user_config():
155
125
  config_data = {}
156
126
  if not _is_remote() and os.path.exists(user_config_path):
@@ -298,8 +298,7 @@ class _Dict(_Object, type_prefix="di"):
298
298
  )
299
299
 
300
300
  @classproperty
301
- @classmethod
302
- def objects(cls) -> type[_DictManager]:
301
+ def objects(cls) -> _DictManager:
303
302
  return _DictManager
304
303
 
305
304
  @property
@@ -412,8 +412,7 @@ class _Dict(modal._object._Object):
412
412
  ...
413
413
 
414
414
  @synchronicity.classproperty
415
- @classmethod
416
- def objects(cls) -> type[_DictManager]: ...
415
+ def objects(cls) -> _DictManager: ...
417
416
  @property
418
417
  def name(self) -> typing.Optional[str]: ...
419
418
  def _hydrate_metadata(self, metadata: typing.Optional[google.protobuf.message.Message]): ...
@@ -654,8 +653,7 @@ class Dict(modal.object.Object):
654
653
  ...
655
654
 
656
655
  @synchronicity.classproperty
657
- @classmethod
658
- def objects(cls) -> type[DictManager]: ...
656
+ def objects(cls) -> DictManager: ...
659
657
  @property
660
658
  def name(self) -> typing.Optional[str]: ...
661
659
  def _hydrate_metadata(self, metadata: typing.Optional[google.protobuf.message.Message]): ...
@@ -348,7 +348,7 @@ class Function(
348
348
 
349
349
  _call_generator: ___call_generator_spec
350
350
 
351
- class __remote_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER]):
351
+ class __remote_spec(typing_extensions.Protocol[ReturnType_INNER, P_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.P, modal._functions.ReturnType]
360
+ remote: __remote_spec[modal._functions.ReturnType, modal._functions.P]
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[P_INNER, ReturnType_INNER]):
387
+ class ___experimental_spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_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.P, modal._functions.ReturnType]
410
+ _experimental_spawn: ___experimental_spawn_spec[modal._functions.ReturnType, modal._functions.P]
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[P_INNER, ReturnType_INNER]):
418
+ class __spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_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.P, modal._functions.ReturnType]
439
+ spawn: __spawn_spec[modal._functions.ReturnType, modal._functions.P]
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."""
@@ -699,18 +699,16 @@ Mount = synchronize_api(_Mount)
699
699
 
700
700
  def _create_client_mount():
701
701
  # TODO(erikbern): make this a static method on the Mount class
702
- import importlib
703
-
704
702
  import synchronicity
705
703
 
704
+ import modal
705
+
706
+ # Get the base_path because it also contains `modal_proto`.
707
+ modal_parent_dir, _ = os.path.split(modal.__path__[0])
706
708
  client_mount = _Mount._new()
707
709
 
708
710
  for pkg_name in MODAL_PACKAGES:
709
- # Look up each package's actual install path via importlib rather than
710
- # assuming all packages are siblings of `modal`. In Bazel runfiles,
711
- # modal and modal_proto live in different directories.
712
- pkg_module = importlib.import_module(pkg_name)
713
- package_base_path = Path(pkg_module.__path__[0])
711
+ package_base_path = Path(modal_parent_dir) / pkg_name
714
712
  client_mount = client_mount.add_local_dir(
715
713
  package_base_path,
716
714
  remote_path=f"/pkg/{pkg_name}",
@@ -291,8 +291,7 @@ class _Queue(_Object, type_prefix="qu"):
291
291
  raise RuntimeError("Queue() is not allowed. Please use `Queue.from_name(...)` or `Queue.ephemeral()` instead.")
292
292
 
293
293
  @classproperty
294
- @classmethod
295
- def objects(cls) -> type[_QueueManager]:
294
+ def objects(cls) -> _QueueManager:
296
295
  return _QueueManager
297
296
 
298
297
  @property
@@ -431,8 +431,7 @@ class _Queue(modal._object._Object):
431
431
  ...
432
432
 
433
433
  @synchronicity.classproperty
434
- @classmethod
435
- def objects(cls) -> type[_QueueManager]: ...
434
+ def objects(cls) -> _QueueManager: ...
436
435
  @property
437
436
  def name(self) -> typing.Optional[str]: ...
438
437
  def _hydrate_metadata(self, metadata: typing.Optional[google.protobuf.message.Message]): ...
@@ -727,8 +726,7 @@ class Queue(modal.object.Object):
727
726
  ...
728
727
 
729
728
  @synchronicity.classproperty
730
- @classmethod
731
- def objects(cls) -> type[QueueManager]: ...
729
+ def objects(cls) -> QueueManager: ...
732
730
  @property
733
731
  def name(self) -> typing.Optional[str]: ...
734
732
  def _hydrate_metadata(self, metadata: typing.Optional[google.protobuf.message.Message]): ...
@@ -42,7 +42,6 @@ from .exception import (
42
42
  InvalidError,
43
43
  SandboxTerminatedError,
44
44
  SandboxTimeoutError,
45
- TimeoutError,
46
45
  )
47
46
  from .file_io import FileWatchEvent, FileWatchEventType, _FileIO, ls, mkdir, rm, watch
48
47
  from .image import _Image
@@ -119,73 +118,6 @@ class SandboxConnectCredentials:
119
118
  token: str
120
119
 
121
120
 
122
- @dataclass(frozen=True)
123
- class Probe:
124
- """Probe configuration for the Sandbox Readiness Probe.
125
-
126
- Usage:
127
- ```py notest
128
- # Wait until a file exists.
129
- readiness_probe = modal.Probe.with_exec(
130
- "sh", "-c", "test -f /tmp/ready",
131
- )
132
-
133
- # Wait until a TCP port is accepting connections.
134
- readiness_probe = modal.Probe.with_tcp(8080)
135
-
136
- app = modal.App.lookup('sandbox-readiness-probe', create_if_missing=True)
137
- sandbox = modal.Sandbox.create(
138
- "python3", "-m", "http.server", "8080",
139
- readiness_probe=readiness_probe,
140
- app=app,
141
- )
142
- sandbox.wait_until_ready()
143
- ```
144
- """
145
-
146
- tcp_port: Optional[int] = None
147
- exec_argv: Optional[tuple[str, ...]] = None
148
- interval_ms: int = 100
149
-
150
- def __post_init__(self):
151
- if (self.tcp_port is None) == (self.exec_argv is None):
152
- raise InvalidError("Probe must be created with Probe.with_tcp(...) or Probe.with_exec(...)")
153
-
154
- @classmethod
155
- def with_tcp(cls, port: int, *, interval_ms: int = 100) -> "Probe":
156
- if not isinstance(port, int):
157
- raise InvalidError("Probe.with_tcp() expects an integer `port`")
158
- if port <= 0 or port > 65535:
159
- raise InvalidError(f"Probe.with_tcp() expects `port` in [1, 65535], got {port}")
160
- if not isinstance(interval_ms, int):
161
- raise InvalidError("Probe.with_tcp() expects an integer `interval_ms`")
162
- if interval_ms <= 0:
163
- raise InvalidError(f"Probe.with_tcp() expects `interval_ms` > 0, got {interval_ms}")
164
- return cls(tcp_port=port, interval_ms=interval_ms)
165
-
166
- @classmethod
167
- def with_exec(cls, *argv: str, interval_ms: int = 100) -> "Probe":
168
- if len(argv) == 0:
169
- raise InvalidError("Probe.with_exec() requires at least one argument")
170
- if not all(isinstance(arg, str) for arg in argv):
171
- raise InvalidError("Probe.with_exec() expects all arguments to be strings")
172
- if not isinstance(interval_ms, int):
173
- raise InvalidError("Probe.with_exec() expects an integer `interval_ms`")
174
- if interval_ms <= 0:
175
- raise InvalidError(f"Probe.with_exec() expects `interval_ms` > 0, got {interval_ms}")
176
- return cls(exec_argv=tuple(argv), interval_ms=interval_ms)
177
-
178
- def _to_proto(self) -> api_pb2.Probe:
179
- if self.tcp_port is not None:
180
- return api_pb2.Probe(tcp_port=self.tcp_port, interval_ms=self.interval_ms)
181
- if self.exec_argv is not None:
182
- return api_pb2.Probe(
183
- exec_command=api_pb2.Probe.ExecCommand(argv=list(self.exec_argv)),
184
- interval_ms=self.interval_ms,
185
- )
186
- raise InvalidError("Probe must be created with Probe.with_tcp(...) or Probe.with_exec(...)")
187
-
188
-
189
121
  class _Sandbox(_Object, type_prefix="sb"):
190
122
  """A `Sandbox` object lets you interact with a running sandbox. This API is similar to Python's
191
123
  [asyncio.subprocess.Process](https://docs.python.org/3/library/asyncio-subprocess.html#asyncio.subprocess.Process).
@@ -234,7 +166,6 @@ class _Sandbox(_Object, type_prefix="sb"):
234
166
  h2_ports: Sequence[int] = [],
235
167
  unencrypted_ports: Sequence[int] = [],
236
168
  proxy: Optional[_Proxy] = None,
237
- readiness_probe: Optional[Probe] = None,
238
169
  experimental_options: Optional[dict[str, bool]] = None,
239
170
  enable_snapshot: bool = False,
240
171
  verbose: bool = False,
@@ -348,7 +279,6 @@ class _Sandbox(_Object, type_prefix="sb"):
348
279
  open_ports=api_pb2.PortSpecs(ports=open_ports),
349
280
  network_access=network_access,
350
281
  proxy_id=(proxy.object_id if proxy else None),
351
- readiness_probe=(readiness_probe._to_proto() if readiness_probe else None),
352
282
  enable_snapshot=enable_snapshot,
353
283
  verbose=verbose,
354
284
  name=name,
@@ -409,8 +339,6 @@ class _Sandbox(_Object, type_prefix="sb"):
409
339
  proxy: Optional[_Proxy] = None,
410
340
  # If True, the sandbox will receive a MODAL_IDENTITY_TOKEN env var for OIDC-based auth.
411
341
  include_oidc_identity_token: bool = False,
412
- # Probe used to determine when the sandbox has become ready.
413
- readiness_probe: Optional[Probe] = None,
414
342
  # Enable verbose logging for sandbox operations.
415
343
  verbose: bool = False,
416
344
  experimental_options: Optional[dict[str, bool]] = None,
@@ -475,7 +403,6 @@ class _Sandbox(_Object, type_prefix="sb"):
475
403
  h2_ports=h2_ports,
476
404
  unencrypted_ports=unencrypted_ports,
477
405
  proxy=proxy,
478
- readiness_probe=readiness_probe,
479
406
  experimental_options=experimental_options,
480
407
  _experimental_enable_snapshot=_experimental_enable_snapshot,
481
408
  include_oidc_identity_token=include_oidc_identity_token,
@@ -512,7 +439,6 @@ class _Sandbox(_Object, type_prefix="sb"):
512
439
  unencrypted_ports: Sequence[int] = [],
513
440
  proxy: Optional[_Proxy] = None,
514
441
  include_oidc_identity_token: bool = False,
515
- readiness_probe: Optional[Probe] = None,
516
442
  experimental_options: Optional[dict[str, bool]] = None,
517
443
  _experimental_enable_snapshot: bool = False,
518
444
  client: Optional[_Client] = None,
@@ -564,7 +490,6 @@ class _Sandbox(_Object, type_prefix="sb"):
564
490
  h2_ports=h2_ports,
565
491
  unencrypted_ports=unencrypted_ports,
566
492
  proxy=proxy,
567
- readiness_probe=readiness_probe,
568
493
  experimental_options=experimental_options,
569
494
  enable_snapshot=_experimental_enable_snapshot,
570
495
  verbose=verbose,
@@ -1033,39 +958,6 @@ class _Sandbox(_Object, type_prefix="sb"):
1033
958
  raise SandboxTerminatedError()
1034
959
  break
1035
960
 
1036
- async def wait_until_ready(self, *, timeout: int = 300) -> None:
1037
- """Wait for the Sandbox readiness probe to report that the Sandbox is ready.
1038
-
1039
- The Sandbox must be configured with a `readiness_probe` in order to use this method.
1040
-
1041
- Usage:
1042
- ```py notest
1043
- app = modal.App.lookup('sandbox-wait-until-ready', create_if_missing=True)
1044
- sandbox = modal.Sandbox.create(
1045
- "python3", "-m", "http.server", "8080",
1046
- readiness_probe=modal.Probe.with_tcp(8080),
1047
- app=app,
1048
- )
1049
- sandbox.wait_until_ready()
1050
- ```
1051
- """
1052
- if timeout <= 0:
1053
- raise InvalidError(f"`timeout` must be positive, got: {timeout}")
1054
-
1055
- deadline = time.monotonic() + timeout
1056
- remaining_timeout = deadline - time.monotonic()
1057
- while remaining_timeout > 0:
1058
- req = api_pb2.SandboxWaitUntilReadyRequest(
1059
- sandbox_id=self.object_id,
1060
- timeout=min(remaining_timeout, 50.0),
1061
- )
1062
- resp = await self._client.stub.SandboxWaitUntilReady(req)
1063
- if resp.ready_at > 0:
1064
- return
1065
-
1066
- remaining_timeout = deadline - time.monotonic()
1067
- raise TimeoutError()
1068
-
1069
961
  async def tunnels(self, timeout: int = 50) -> dict[int, Tunnel]:
1070
962
  """Get Tunnel metadata for the sandbox.
1071
963