modal 1.4.3.dev6__tar.gz → 1.4.3.dev8__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 (212) hide show
  1. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/PKG-INFO +1 -1
  2. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_utils/async_utils.py +1 -1
  3. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_utils/sandbox_fs_utils.py +60 -30
  4. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/cli/cluster.py +25 -7
  5. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/cli/container.py +22 -7
  6. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/client.pyi +2 -2
  7. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/file_io.py +1 -1
  8. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/sandbox.py +11 -3
  9. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/sandbox.pyi +18 -6
  10. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/sandbox_fs.py +242 -146
  11. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/sandbox_fs.pyi +375 -233
  12. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal.egg-info/PKG-INFO +1 -1
  13. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal_proto/task_command_router_grpc.py +32 -0
  14. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal_proto/task_command_router_pb2.py +109 -63
  15. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal_proto/task_command_router_pb2.pyi +81 -0
  16. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal_proto/task_command_router_pb2_grpc.py +66 -0
  17. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal_proto/task_command_router_pb2_grpc.pyi +20 -0
  18. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal_version/__init__.py +1 -1
  19. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/LICENSE +0 -0
  20. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/README.md +0 -0
  21. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/__init__.py +0 -0
  22. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/__main__.py +0 -0
  23. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_billing.py +0 -0
  24. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_clustered_functions.py +0 -0
  25. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_clustered_functions.pyi +0 -0
  26. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_container_entrypoint.py +0 -0
  27. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_functions.py +0 -0
  28. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_grpc_client.py +0 -0
  29. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_ipython.py +0 -0
  30. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_load_context.py +0 -0
  31. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_location.py +0 -0
  32. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_logs.py +0 -0
  33. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_object.py +0 -0
  34. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_output/__init__.py +0 -0
  35. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_output/manager.py +0 -0
  36. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_output/pty.py +0 -0
  37. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_output/rich.py +0 -0
  38. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_output/status.py +0 -0
  39. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_partial_function.py +0 -0
  40. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_resolver.py +0 -0
  41. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_resources.py +0 -0
  42. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_runtime/__init__.py +0 -0
  43. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_runtime/asgi.py +0 -0
  44. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_runtime/container_io_manager.py +0 -0
  45. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_runtime/container_io_manager.pyi +0 -0
  46. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_runtime/execution_context.py +0 -0
  47. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_runtime/execution_context.pyi +0 -0
  48. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_runtime/gpu_memory_snapshot.py +0 -0
  49. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_runtime/telemetry.py +0 -0
  50. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_runtime/user_code_event_loop.py +0 -0
  51. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_runtime/user_code_imports.py +0 -0
  52. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_serialization.py +0 -0
  53. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_server.py +0 -0
  54. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_traceback.py +0 -0
  55. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_tunnel.py +0 -0
  56. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_tunnel.pyi +0 -0
  57. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_type_manager.py +0 -0
  58. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_utils/__init__.py +0 -0
  59. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_utils/app_utils.py +0 -0
  60. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_utils/auth_token_manager.py +0 -0
  61. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_utils/blob_utils.py +0 -0
  62. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_utils/browser_utils.py +0 -0
  63. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_utils/bytes_io_segment_payload.py +0 -0
  64. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_utils/deprecation.py +0 -0
  65. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_utils/docker_utils.py +0 -0
  66. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_utils/function_utils.py +0 -0
  67. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_utils/git_utils.py +0 -0
  68. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_utils/grpc_testing.py +0 -0
  69. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_utils/grpc_utils.py +0 -0
  70. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_utils/hash_utils.py +0 -0
  71. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_utils/http_utils.py +0 -0
  72. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_utils/jwt_utils.py +0 -0
  73. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_utils/logger.py +0 -0
  74. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_utils/mount_utils.py +0 -0
  75. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_utils/name_utils.py +0 -0
  76. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_utils/package_utils.py +0 -0
  77. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_utils/pattern_utils.py +0 -0
  78. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_utils/rand_pb_testing.py +0 -0
  79. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_utils/shell_utils.py +0 -0
  80. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_utils/task_command_router_client.py +0 -0
  81. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_utils/time_utils.py +0 -0
  82. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_vendor/__init__.py +0 -0
  83. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_vendor/a2wsgi_wsgi.py +0 -0
  84. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_vendor/cloudpickle.py +0 -0
  85. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_vendor/tblib.py +0 -0
  86. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_vendor/version.py +0 -0
  87. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/_watcher.py +0 -0
  88. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/app.py +0 -0
  89. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/app.pyi +0 -0
  90. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/billing.py +0 -0
  91. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/builder/2023.12.312.txt +0 -0
  92. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/builder/2023.12.txt +0 -0
  93. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/builder/2024.04.txt +0 -0
  94. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/builder/2024.10.txt +0 -0
  95. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/builder/2025.06.txt +0 -0
  96. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/builder/PREVIEW.txt +0 -0
  97. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/builder/README.md +0 -0
  98. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/builder/base-images.json +0 -0
  99. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/call_graph.py +0 -0
  100. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/cli/__init__.py +0 -0
  101. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/cli/_download.py +0 -0
  102. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/cli/_help.py +0 -0
  103. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/cli/_traceback.py +0 -0
  104. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/cli/app.py +0 -0
  105. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/cli/billing.py +0 -0
  106. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/cli/bootstrap.py +0 -0
  107. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/cli/changelog.py +0 -0
  108. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/cli/config.py +0 -0
  109. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/cli/dashboard.py +0 -0
  110. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/cli/dict.py +0 -0
  111. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/cli/entry_point.py +0 -0
  112. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/cli/environment.py +0 -0
  113. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/cli/import_refs.py +0 -0
  114. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/cli/launch.py +0 -0
  115. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/cli/logo.py +0 -0
  116. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/cli/network_file_system.py +0 -0
  117. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/cli/profile.py +0 -0
  118. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/cli/programs/__init__.py +0 -0
  119. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/cli/programs/run_jupyter.py +0 -0
  120. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/cli/programs/vscode.py +0 -0
  121. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/cli/queues.py +0 -0
  122. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/cli/run.py +0 -0
  123. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/cli/secret.py +0 -0
  124. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/cli/selector.py +0 -0
  125. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/cli/shell.py +0 -0
  126. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/cli/token.py +0 -0
  127. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/cli/utils.py +0 -0
  128. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/cli/volume.py +0 -0
  129. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/client.py +0 -0
  130. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/cloud_bucket_mount.py +0 -0
  131. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/cloud_bucket_mount.pyi +0 -0
  132. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/cls.py +0 -0
  133. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/cls.pyi +0 -0
  134. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/config.py +0 -0
  135. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/container_process.py +0 -0
  136. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/container_process.pyi +0 -0
  137. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/dict.py +0 -0
  138. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/dict.pyi +0 -0
  139. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/environments.py +0 -0
  140. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/environments.pyi +0 -0
  141. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/exception.py +0 -0
  142. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/experimental/__init__.py +0 -0
  143. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/experimental/flash.py +0 -0
  144. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/experimental/flash.pyi +0 -0
  145. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/experimental/ipython.py +0 -0
  146. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/file_io.pyi +0 -0
  147. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/file_pattern_matcher.py +0 -0
  148. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/functions.py +0 -0
  149. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/functions.pyi +0 -0
  150. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/image.py +0 -0
  151. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/image.pyi +0 -0
  152. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/io_streams.py +0 -0
  153. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/io_streams.pyi +0 -0
  154. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/mount.py +0 -0
  155. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/mount.pyi +0 -0
  156. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/network_file_system.py +0 -0
  157. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/network_file_system.pyi +0 -0
  158. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/object.py +0 -0
  159. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/object.pyi +0 -0
  160. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/output.py +0 -0
  161. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/parallel_map.py +0 -0
  162. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/parallel_map.pyi +0 -0
  163. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/partial_function.py +0 -0
  164. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/partial_function.pyi +0 -0
  165. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/proxy.py +0 -0
  166. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/proxy.pyi +0 -0
  167. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/py.typed +0 -0
  168. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/queue.py +0 -0
  169. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/queue.pyi +0 -0
  170. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/retries.py +0 -0
  171. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/runner.py +0 -0
  172. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/runner.pyi +0 -0
  173. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/running_app.py +0 -0
  174. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/schedule.py +0 -0
  175. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/scheduler_placement.py +0 -0
  176. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/secret.py +0 -0
  177. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/secret.pyi +0 -0
  178. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/server.py +0 -0
  179. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/server.pyi +0 -0
  180. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/serving.py +0 -0
  181. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/serving.pyi +0 -0
  182. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/snapshot.py +0 -0
  183. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/snapshot.pyi +0 -0
  184. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/stream_type.py +0 -0
  185. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/token_flow.py +0 -0
  186. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/token_flow.pyi +0 -0
  187. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/volume.py +0 -0
  188. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal/volume.pyi +0 -0
  189. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal.egg-info/SOURCES.txt +0 -0
  190. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal.egg-info/dependency_links.txt +0 -0
  191. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal.egg-info/entry_points.txt +0 -0
  192. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal.egg-info/requires.txt +0 -0
  193. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal.egg-info/top_level.txt +0 -0
  194. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal_docs/__init__.py +0 -0
  195. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal_docs/gen_cli_docs.py +0 -0
  196. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal_docs/gen_cli_docs_main.py +0 -0
  197. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal_docs/gen_reference_docs.py +0 -0
  198. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal_docs/gen_reference_docs_main.py +0 -0
  199. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal_docs/mdmd/__init__.py +0 -0
  200. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal_docs/mdmd/mdmd.py +0 -0
  201. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal_docs/mdmd/signatures.py +0 -0
  202. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal_proto/__init__.py +0 -0
  203. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal_proto/api_grpc.py +0 -0
  204. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal_proto/api_pb2.py +0 -0
  205. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal_proto/api_pb2.pyi +0 -0
  206. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal_proto/api_pb2_grpc.py +0 -0
  207. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal_proto/api_pb2_grpc.pyi +0 -0
  208. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal_proto/modal_api_grpc.py +0 -0
  209. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal_proto/py.typed +0 -0
  210. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/modal_version/__main__.py +0 -0
  211. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/pyproject.toml +0 -0
  212. {modal-1.4.3.dev6 → modal-1.4.3.dev8}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.4.3.dev6
3
+ Version: 1.4.3.dev8
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License-Expression: Apache-2.0
@@ -1115,7 +1115,7 @@ async def async_merge(
1115
1115
  new_output_task = asyncio.create_task(queue.get())
1116
1116
 
1117
1117
  finally:
1118
- unfinished_tasks = [t for t in tasks | {new_output_task} if not t.done()]
1118
+ unfinished_tasks: list[asyncio.Task[Any]] = [t for t in tasks | {new_output_task} if not t.done()]
1119
1119
  for t in unfinished_tasks:
1120
1120
  t.cancel()
1121
1121
  try:
@@ -60,27 +60,6 @@ def try_parse_error_payload(stderr: Union[str, bytes]) -> Optional[ErrorPayload]
60
60
  return ErrorPayload(error_kind=error_kind, message=message, detail=detail)
61
61
 
62
62
 
63
- def raise_read_file_error(returncode: int, stderr: Union[str, bytes], remote_path: str) -> NoReturn:
64
- if payload := try_parse_error_payload(stderr):
65
- logger.debug(
66
- f"sandbox-fs-tools read error: path={remote_path}, "
67
- f"error_kind={payload.error_kind}, message={payload.message}, detail={payload.detail}"
68
- )
69
- if payload.error_kind == "NotFound":
70
- raise SandboxFilesystemNotFoundError(f"{payload.message}: {remote_path}")
71
- if payload.error_kind == "IsDirectory":
72
- raise SandboxFilesystemIsADirectoryError(f"{payload.message}: {remote_path}")
73
- if payload.error_kind == "PermissionDenied":
74
- raise SandboxFilesystemPermissionError(f"{payload.message}: {remote_path}")
75
- if payload.error_kind == "FileTooLarge":
76
- raise SandboxFilesystemFileTooLargeError(f"{payload.message}: {remote_path}")
77
- raise SandboxFilesystemError(payload.message)
78
-
79
- if stderr_text := _stderr_to_text(stderr):
80
- logger.debug(f"Unstructured modal-sandbox-fs-tools stderr: {stderr_text}")
81
- raise SandboxFilesystemError(f"Operation on '{remote_path}' failed with exit code {returncode}")
82
-
83
-
84
63
  def _extract_support_error_code(exc: Exception) -> Optional[str]:
85
64
  if match := re.search(r"Error code:\s*([A-Z0-9]{8})", str(exc)):
86
65
  return match.group(1)
@@ -144,26 +123,66 @@ def make_write_file_command(remote_path: str) -> str:
144
123
  return json.dumps({"WriteFile": {"path": remote_path}})
145
124
 
146
125
 
147
- def make_read_file_command(remote_path: str) -> str:
148
- """Build the JSON command string for a ReadFile operation.
126
+ def raise_list_files_error(returncode: int, stderr: Union[str, bytes], remote_path: str) -> NoReturn:
127
+ if payload := try_parse_error_payload(stderr):
128
+ logger.debug(
129
+ f"sandbox-fs-tools list_files error: path={remote_path}, "
130
+ f"error_kind={payload.error_kind}, message={payload.message}, detail={payload.detail}"
131
+ )
132
+ if payload.error_kind == "NotFound":
133
+ raise SandboxFilesystemNotFoundError(f"{payload.message}: {remote_path}")
134
+ if payload.error_kind in ("IsFile", "NotDirectory"):
135
+ raise SandboxFilesystemNotADirectoryError(f"{payload.message}: {remote_path}")
136
+ if payload.error_kind == "PermissionDenied":
137
+ raise SandboxFilesystemPermissionError(f"{payload.message}: {remote_path}")
138
+ raise SandboxFilesystemError(payload.message)
139
+
140
+ if stderr_text := _stderr_to_text(stderr):
141
+ logger.debug(f"Unstructured modal-sandbox-fs-tools stderr: {stderr_text}")
142
+ raise SandboxFilesystemError(f"Operation on '{remote_path}' failed with exit code {returncode}")
143
+
144
+
145
+ def make_list_files_command(remote_path: str) -> str:
146
+ """Build the JSON command string for a ListFiles operation.
149
147
 
150
148
  The returned JSON must match the `Command` enum in the modal-sandbox-fs-tools
151
149
  Rust crate (crates/modal-sandbox-fs-tools/src/lib.rs). Treat changes to
152
150
  this schema like protobuf changes: fields must not be removed or renamed,
153
151
  only added with backwards-compatible defaults.
154
152
  """
155
- return json.dumps({"ReadFile": {"path": remote_path}})
153
+ return json.dumps({"ListFiles": {"path": remote_path}})
156
154
 
157
155
 
158
- def make_remove_command(remote_path: str, recursive: bool) -> str:
159
- """Build the JSON command string for a Remove operation.
156
+ def raise_read_file_error(returncode: int, stderr: Union[str, bytes], remote_path: str) -> NoReturn:
157
+ if payload := try_parse_error_payload(stderr):
158
+ logger.debug(
159
+ f"sandbox-fs-tools read error: path={remote_path}, "
160
+ f"error_kind={payload.error_kind}, message={payload.message}, detail={payload.detail}"
161
+ )
162
+ if payload.error_kind == "NotFound":
163
+ raise SandboxFilesystemNotFoundError(f"{payload.message}: {remote_path}")
164
+ if payload.error_kind == "IsDirectory":
165
+ raise SandboxFilesystemIsADirectoryError(f"{payload.message}: {remote_path}")
166
+ if payload.error_kind == "PermissionDenied":
167
+ raise SandboxFilesystemPermissionError(f"{payload.message}: {remote_path}")
168
+ if payload.error_kind == "FileTooLarge":
169
+ raise SandboxFilesystemFileTooLargeError(f"{payload.message}: {remote_path}")
170
+ raise SandboxFilesystemError(payload.message)
171
+
172
+ if stderr_text := _stderr_to_text(stderr):
173
+ logger.debug(f"Unstructured modal-sandbox-fs-tools stderr: {stderr_text}")
174
+ raise SandboxFilesystemError(f"Operation on '{remote_path}' failed with exit code {returncode}")
175
+
176
+
177
+ def make_read_file_command(remote_path: str) -> str:
178
+ """Build the JSON command string for a ReadFile operation.
160
179
 
161
180
  The returned JSON must match the `Command` enum in the modal-sandbox-fs-tools
162
181
  Rust crate (crates/modal-sandbox-fs-tools/src/lib.rs). Treat changes to
163
182
  this schema like protobuf changes: fields must not be removed or renamed,
164
183
  only added with backwards-compatible defaults.
165
184
  """
166
- return json.dumps({"Remove": {"path": remote_path, "recursive": recursive}})
185
+ return json.dumps({"ReadFile": {"path": remote_path}})
167
186
 
168
187
 
169
188
  def raise_remove_error(returncode: int, stderr: Union[str, bytes], remote_path: str) -> NoReturn:
@@ -189,15 +208,15 @@ def raise_remove_error(returncode: int, stderr: Union[str, bytes], remote_path:
189
208
  raise SandboxFilesystemError(f"Operation on '{remote_path}' failed with exit code {returncode}")
190
209
 
191
210
 
192
- def make_make_directory_command(remote_path: str, create_parents: bool) -> str:
193
- """Build the JSON command string for a MakeDirectory operation.
211
+ def make_remove_command(remote_path: str, recursive: bool) -> str:
212
+ """Build the JSON command string for a Remove operation.
194
213
 
195
214
  The returned JSON must match the `Command` enum in the modal-sandbox-fs-tools
196
215
  Rust crate (crates/modal-sandbox-fs-tools/src/lib.rs). Treat changes to
197
216
  this schema like protobuf changes: fields must not be removed or renamed,
198
217
  only added with backwards-compatible defaults.
199
218
  """
200
- return json.dumps({"MakeDirectory": {"path": remote_path, "parents": create_parents}})
219
+ return json.dumps({"Remove": {"path": remote_path, "recursive": recursive}})
201
220
 
202
221
 
203
222
  def raise_make_directory_error(returncode: int, stderr: Union[str, bytes], remote_path: str) -> NoReturn:
@@ -225,6 +244,17 @@ def raise_make_directory_error(returncode: int, stderr: Union[str, bytes], remot
225
244
  raise SandboxFilesystemError(f"Operation on '{remote_path}' failed with exit code {returncode}")
226
245
 
227
246
 
247
+ def make_make_directory_command(remote_path: str, create_parents: bool) -> str:
248
+ """Build the JSON command string for a MakeDirectory operation.
249
+
250
+ The returned JSON must match the `Command` enum in the modal-sandbox-fs-tools
251
+ Rust crate (crates/modal-sandbox-fs-tools/src/lib.rs). Treat changes to
252
+ this schema like protobuf changes: fields must not be removed or renamed,
253
+ only added with backwards-compatible defaults.
254
+ """
255
+ return json.dumps({"MakeDirectory": {"path": remote_path, "parents": create_parents}})
256
+
257
+
228
258
  def validate_absolute_remote_path(remote_path: str, operation: str) -> None:
229
259
  if not PurePosixPath(remote_path).is_absolute():
230
260
  raise InvalidError(f"Sandbox.filesystem.{operation}() currently only supports absolute remote_path values")
@@ -1,4 +1,5 @@
1
1
  # Copyright Modal Labs 2022
2
+ import uuid
2
3
  from typing import Optional, Union
3
4
 
4
5
  import click
@@ -8,15 +9,17 @@ from rich.text import Text
8
9
  from modal._object import _get_environment_name
9
10
  from modal._output.pty import get_pty_info
10
11
  from modal._utils.async_utils import synchronizer
12
+ from modal._utils.task_command_router_client import TaskCommandRouterClient
11
13
  from modal._utils.time_utils import timestamp_to_localized_str
12
14
  from modal.cli.utils import display_table, env_option, is_tty
13
15
  from modal.client import _Client
14
16
  from modal.config import config
15
17
  from modal.container_process import _ContainerProcess
16
18
  from modal.environments import ensure_env
19
+ from modal.exception import InvalidError
17
20
  from modal.output import OutputManager
18
21
  from modal.stream_type import StreamType
19
- from modal_proto import api_pb2
22
+ from modal_proto import api_pb2, task_command_router_pb2 as sr_pb2
20
23
 
21
24
  from ._help import ModalGroup
22
25
 
@@ -75,17 +78,32 @@ async def shell(cluster_id: str, rank: int = 0):
75
78
  )
76
79
 
77
80
  pty = is_tty()
78
- req = api_pb2.ContainerExecRequest(
81
+
82
+ command_router_client = await TaskCommandRouterClient.try_init(client, task_id)
83
+ if command_router_client is None:
84
+ raise InvalidError(f"Command router access is not available for container {task_id}")
85
+
86
+ process_id = str(uuid.uuid4())
87
+
88
+ start_req = sr_pb2.TaskExecStartRequest(
79
89
  task_id=task_id,
80
- command=["/bin/bash"],
90
+ exec_id=process_id,
91
+ command_args=["/bin/bash"],
92
+ stdout_config=sr_pb2.TaskExecStdoutConfig.TASK_EXEC_STDOUT_CONFIG_PIPE,
93
+ stderr_config=sr_pb2.TaskExecStderrConfig.TASK_EXEC_STDERR_CONFIG_PIPE,
81
94
  pty_info=get_pty_info(shell=True) if pty else None,
82
95
  runtime_debug=config.get("function_runtime_debug"),
83
96
  )
84
- exec_res: api_pb2.ContainerExecResponse = await client.stub.ContainerExec(req)
97
+ await command_router_client.exec_start(start_req)
98
+
85
99
  if pty:
86
- await _ContainerProcess(exec_res.exec_id, task_id, client).attach()
100
+ await _ContainerProcess(process_id, task_id, client, command_router_client=command_router_client).attach()
87
101
  else:
88
- # TODO: redirect stderr to its own stream?
89
102
  await _ContainerProcess(
90
- exec_res.exec_id, task_id, client, stdout=StreamType.STDOUT, stderr=StreamType.STDOUT
103
+ process_id,
104
+ task_id,
105
+ client,
106
+ command_router_client=command_router_client,
107
+ stdout=StreamType.STDOUT,
108
+ stderr=StreamType.STDOUT,
91
109
  ).wait()
@@ -1,4 +1,5 @@
1
1
  # Copyright Modal Labs 2022
2
+ import uuid
2
3
  import warnings
3
4
  from datetime import datetime, timezone
4
5
  from typing import Optional, Union
@@ -12,6 +13,7 @@ from modal._logs import _FETCH_LIMIT, _MAX_FETCH_RANGE, LogsFilters
12
13
  from modal._object import _get_environment_name
13
14
  from modal._output.pty import get_pty_info
14
15
  from modal._utils.async_utils import synchronizer
16
+ from modal._utils.task_command_router_client import TaskCommandRouterClient
15
17
  from modal._utils.time_utils import timestamp_to_localized_str
16
18
  from modal.cli.app import _DEFAULT_LOGS_TAIL, _SOURCE_OPTIONS, _parse_time_arg
17
19
  from modal.cli.utils import (
@@ -30,7 +32,7 @@ from modal.container_process import _ContainerProcess
30
32
  from modal.environments import ensure_env
31
33
  from modal.exception import InvalidError
32
34
  from modal.stream_type import StreamType
33
- from modal_proto import api_pb2
35
+ from modal_proto import api_pb2, task_command_router_pb2 as sr_pb2
34
36
 
35
37
  from ._help import ModalGroup
36
38
 
@@ -276,20 +278,33 @@ async def _exec_impl(
276
278
 
277
279
  client = await _Client.from_env()
278
280
 
279
- req = api_pb2.ContainerExecRequest(
281
+ command_router_client = await TaskCommandRouterClient.try_init(client, container_id)
282
+ if command_router_client is None:
283
+ raise InvalidError(f"Command router access is not available for container {container_id}")
284
+
285
+ process_id = str(uuid.uuid4())
286
+
287
+ start_req = sr_pb2.TaskExecStartRequest(
280
288
  task_id=container_id,
281
- command=command,
289
+ exec_id=process_id,
290
+ command_args=command,
291
+ stdout_config=sr_pb2.TaskExecStdoutConfig.TASK_EXEC_STDOUT_CONFIG_PIPE,
292
+ stderr_config=sr_pb2.TaskExecStderrConfig.TASK_EXEC_STDERR_CONFIG_PIPE,
282
293
  pty_info=get_pty_info(shell=True) if pty else None,
283
294
  runtime_debug=config.get("function_runtime_debug"),
284
295
  )
285
- res: api_pb2.ContainerExecResponse = await client.stub.ContainerExec(req)
296
+ await command_router_client.exec_start(start_req)
286
297
 
287
298
  if pty:
288
- await _ContainerProcess(res.exec_id, container_id, client).attach()
299
+ await _ContainerProcess(process_id, container_id, client, command_router_client=command_router_client).attach()
289
300
  else:
290
- # TODO: redirect stderr to its own stream?
291
301
  await _ContainerProcess(
292
- res.exec_id, container_id, client, stdout=StreamType.STDOUT, stderr=StreamType.STDOUT
302
+ process_id,
303
+ container_id,
304
+ client,
305
+ command_router_client=command_router_client,
306
+ stdout=StreamType.STDOUT,
307
+ stderr=StreamType.STDOUT,
293
308
  ).wait()
294
309
 
295
310
 
@@ -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.3.dev6",
38
+ version: str = "1.4.3.dev8",
39
39
  ):
40
40
  """mdmd:hidden
41
41
  The Modal client object is not intended to be instantiated directly by users.
@@ -175,7 +175,7 @@ class Client:
175
175
  server_url: str,
176
176
  client_type: int,
177
177
  credentials: typing.Optional[tuple[str, str]],
178
- version: str = "1.4.3.dev6",
178
+ version: str = "1.4.3.dev8",
179
179
  ):
180
180
  """mdmd:hidden
181
181
  The Modal client object is not intended to be instantiated directly by users.
@@ -396,7 +396,7 @@ class _FileIO(Generic[T]):
396
396
  """List the contents of the provided directory."""
397
397
  deprecation_warning(
398
398
  (2026, 3, 9),
399
- "`FileIO.ls()` is deprecated. Use `Sandbox.ls()` instead.",
399
+ "`FileIO.ls()` is deprecated. Use `Sandbox.filesystem.list_files()` instead.",
400
400
  pending=True,
401
401
  )
402
402
  return await ls(path, client, task_id)
@@ -628,6 +628,7 @@ class _Sandbox(_Object, type_prefix="sb"):
628
628
  idle_timeout: Optional[int] = None,
629
629
  workdir: Optional[str] = None,
630
630
  cpu: Optional[float] = None,
631
+ memory: Optional[int] = None,
631
632
  cloud: Optional[str] = None,
632
633
  region: Optional[Union[str, Sequence[str]]] = None,
633
634
  block_network: bool = False,
@@ -642,7 +643,6 @@ class _Sandbox(_Object, type_prefix="sb"):
642
643
  ) -> "_Sandbox":
643
644
  """Create a sandbox using the V2 backend.
644
645
 
645
- Only CPU is configurable; memory is derived as a fixed ratio of CPU.
646
646
  Features like tags, snapshots, exec, volumes, network file systems,
647
647
  GPUs, custom domains, and proxies are not supported.
648
648
  """
@@ -714,7 +714,7 @@ class _Sandbox(_Object, type_prefix="sb"):
714
714
  timeout_secs=timeout,
715
715
  idle_timeout_secs=idle_timeout,
716
716
  workdir=workdir,
717
- resources=convert_fn_config_to_resources_config(cpu=cpu, memory=0, gpu=None, ephemeral_disk=None),
717
+ resources=convert_fn_config_to_resources_config(cpu=cpu, memory=memory, gpu=None, ephemeral_disk=None),
718
718
  cloud_provider_str=cloud if cloud else None,
719
719
  runtime=config.get("function_runtime"),
720
720
  runtime_debug=config.get("function_runtime_debug"),
@@ -1641,8 +1641,16 @@ class _Sandbox(_Object, type_prefix="sb"):
1641
1641
  return await _FileIO.create(path, mode, self._client, task_id)
1642
1642
 
1643
1643
  async def ls(self, path: str) -> builtins.list[str]:
1644
- """[Alpha] List the contents of a directory in the Sandbox."""
1644
+ """[Alpha] List the contents of a directory in the Sandbox.
1645
+
1646
+ .. deprecated:: 2026-04-15
1647
+ Use `Sandbox.filesystem.list_files()` instead."""
1645
1648
  self._ensure_v1("ls")
1649
+ deprecation_warning(
1650
+ (2026, 4, 15),
1651
+ "`Sandbox.ls()` is deprecated. Use `Sandbox.filesystem.list_files()` instead.",
1652
+ pending=True,
1653
+ )
1646
1654
  task_id = await self._get_task_id()
1647
1655
  return await ls(path, self._client, task_id)
1648
1656
 
@@ -304,6 +304,7 @@ class _Sandbox(modal._object._Object):
304
304
  idle_timeout: typing.Optional[int] = None,
305
305
  workdir: typing.Optional[str] = None,
306
306
  cpu: typing.Optional[float] = None,
307
+ memory: typing.Optional[int] = None,
307
308
  cloud: typing.Optional[str] = None,
308
309
  region: typing.Union[str, collections.abc.Sequence[str], None] = None,
309
310
  block_network: bool = False,
@@ -318,7 +319,6 @@ class _Sandbox(modal._object._Object):
318
319
  ) -> _Sandbox:
319
320
  """Create a sandbox using the V2 backend.
320
321
 
321
- Only CPU is configurable; memory is derived as a fixed ratio of CPU.
322
322
  Features like tags, snapshots, exec, volumes, network file systems,
323
323
  GPUs, custom domains, and proxies are not supported.
324
324
  """
@@ -613,7 +613,11 @@ class _Sandbox(modal._object._Object):
613
613
  @typing.overload
614
614
  async def open(self, path: str, mode: _typeshed.OpenBinaryMode) -> modal.file_io._FileIO[bytes]: ...
615
615
  async def ls(self, path: str) -> list[str]:
616
- """[Alpha] List the contents of a directory in the Sandbox."""
616
+ """[Alpha] List the contents of a directory in the Sandbox.
617
+
618
+ .. deprecated:: 2026-04-15
619
+ Use `Sandbox.filesystem.list_files()` instead.
620
+ """
617
621
  ...
618
622
 
619
623
  async def mkdir(self, path: str, parents: bool = False) -> None:
@@ -1186,6 +1190,7 @@ class Sandbox(modal.object.Object):
1186
1190
  idle_timeout: typing.Optional[int] = None,
1187
1191
  workdir: typing.Optional[str] = None,
1188
1192
  cpu: typing.Optional[float] = None,
1193
+ memory: typing.Optional[int] = None,
1189
1194
  cloud: typing.Optional[str] = None,
1190
1195
  region: typing.Union[str, collections.abc.Sequence[str], None] = None,
1191
1196
  block_network: bool = False,
@@ -1200,7 +1205,6 @@ class Sandbox(modal.object.Object):
1200
1205
  ) -> Sandbox:
1201
1206
  """Create a sandbox using the V2 backend.
1202
1207
 
1203
- Only CPU is configurable; memory is derived as a fixed ratio of CPU.
1204
1208
  Features like tags, snapshots, exec, volumes, network file systems,
1205
1209
  GPUs, custom domains, and proxies are not supported.
1206
1210
  """
@@ -1219,6 +1223,7 @@ class Sandbox(modal.object.Object):
1219
1223
  idle_timeout: typing.Optional[int] = None,
1220
1224
  workdir: typing.Optional[str] = None,
1221
1225
  cpu: typing.Optional[float] = None,
1226
+ memory: typing.Optional[int] = None,
1222
1227
  cloud: typing.Optional[str] = None,
1223
1228
  region: typing.Union[str, collections.abc.Sequence[str], None] = None,
1224
1229
  block_network: bool = False,
@@ -1233,7 +1238,6 @@ class Sandbox(modal.object.Object):
1233
1238
  ) -> Sandbox:
1234
1239
  """Create a sandbox using the V2 backend.
1235
1240
 
1236
- Only CPU is configurable; memory is derived as a fixed ratio of CPU.
1237
1241
  Features like tags, snapshots, exec, volumes, network file systems,
1238
1242
  GPUs, custom domains, and proxies are not supported.
1239
1243
  """
@@ -1908,11 +1912,19 @@ class Sandbox(modal.object.Object):
1908
1912
 
1909
1913
  class __ls_spec(typing_extensions.Protocol):
1910
1914
  def __call__(self, /, path: str) -> list[str]:
1911
- """[Alpha] List the contents of a directory in the Sandbox."""
1915
+ """[Alpha] List the contents of a directory in the Sandbox.
1916
+
1917
+ .. deprecated:: 2026-04-15
1918
+ Use `Sandbox.filesystem.list_files()` instead.
1919
+ """
1912
1920
  ...
1913
1921
 
1914
1922
  async def aio(self, /, path: str) -> list[str]:
1915
- """[Alpha] List the contents of a directory in the Sandbox."""
1923
+ """[Alpha] List the contents of a directory in the Sandbox.
1924
+
1925
+ .. deprecated:: 2026-04-15
1926
+ Use `Sandbox.filesystem.list_files()` instead.
1927
+ """
1916
1928
  ...
1917
1929
 
1918
1930
  ls: __ls_spec