modal 1.6.2.dev3__tar.gz → 1.6.2.dev4__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 (243) hide show
  1. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/PKG-INFO +1 -1
  2. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_functions.py +2 -2
  3. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/cli/container.py +2 -1
  4. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/cli/shell.py +3 -1
  5. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/client.pyi +2 -2
  6. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/experimental/__init__.py +66 -0
  7. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/functions.pyi +6 -6
  8. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/runner.py +1 -1
  9. modal-1.6.2.dev4/modal/sandbox/__init__.py +9 -0
  10. modal-1.6.2.dev3/modal/sandbox.py → modal-1.6.2.dev4/modal/sandbox/_sandbox.py +38 -53
  11. modal-1.6.2.dev4/modal/sandbox/sandbox.py +9 -0
  12. {modal-1.6.2.dev3/modal → modal-1.6.2.dev4/modal/sandbox}/sandbox.pyi +43 -1371
  13. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/sandbox_fs.py +6 -4
  14. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/sandbox_fs.pyi +10 -5
  15. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/secret.py +13 -4
  16. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/secret.pyi +4 -0
  17. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal.egg-info/PKG-INFO +1 -1
  18. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal.egg-info/SOURCES.txt +4 -2
  19. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal_proto/api_grpc.py +16 -0
  20. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal_proto/api_pb2.py +1275 -1233
  21. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal_proto/api_pb2.pyi +96 -0
  22. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal_proto/api_pb2_grpc.py +33 -0
  23. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal_proto/api_pb2_grpc.pyi +10 -0
  24. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal_proto/modal_api_grpc.py +1 -0
  25. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal_version/__init__.py +1 -1
  26. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/pyproject.toml +5 -2
  27. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/LICENSE +0 -0
  28. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/README.md +0 -0
  29. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/__init__.py +0 -0
  30. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/__main__.py +0 -0
  31. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_billing.py +0 -0
  32. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_cluster.py +0 -0
  33. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_cluster.pyi +0 -0
  34. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_container_entrypoint.py +0 -0
  35. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_environments.py +0 -0
  36. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_function_variants.py +0 -0
  37. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_grpc_client.py +0 -0
  38. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_image.py +0 -0
  39. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_ipython.py +0 -0
  40. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_load_context.py +0 -0
  41. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_location.py +0 -0
  42. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_logs.py +0 -0
  43. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_logs_manager.py +0 -0
  44. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_logs_manager.pyi +0 -0
  45. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_object.py +0 -0
  46. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_outbound_policy.py +0 -0
  47. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_outbound_policy.pyi +0 -0
  48. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_output/__init__.py +0 -0
  49. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_output/manager.py +0 -0
  50. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_output/pty.py +0 -0
  51. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_output/rich.py +0 -0
  52. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_output/status.py +0 -0
  53. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_partial_function.py +0 -0
  54. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_resolver.py +0 -0
  55. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_resources.py +0 -0
  56. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_runtime/__init__.py +0 -0
  57. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_runtime/asgi.py +0 -0
  58. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_runtime/container_io_manager.py +0 -0
  59. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_runtime/container_io_manager.pyi +0 -0
  60. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_runtime/execution_context.py +0 -0
  61. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_runtime/execution_context.pyi +0 -0
  62. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_runtime/gpu_memory_snapshot.py +0 -0
  63. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_runtime/task_lifecycle_manager.py +0 -0
  64. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_runtime/task_lifecycle_manager.pyi +0 -0
  65. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_runtime/telemetry.py +0 -0
  66. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_runtime/user_code_event_loop.py +0 -0
  67. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_runtime/user_code_imports.py +0 -0
  68. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_serialization.py +0 -0
  69. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_server.py +0 -0
  70. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_server.pyi +0 -0
  71. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_supports_logs.py +0 -0
  72. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_traceback.py +0 -0
  73. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_tunnel.py +0 -0
  74. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_tunnel.pyi +0 -0
  75. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_type_manager.py +0 -0
  76. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_utils/__init__.py +0 -0
  77. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_utils/app_utils.py +0 -0
  78. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_utils/async_utils.py +0 -0
  79. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_utils/auth_token_manager.py +0 -0
  80. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_utils/blob_utils.py +0 -0
  81. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_utils/browser_utils.py +0 -0
  82. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_utils/bytes_io_segment_payload.py +0 -0
  83. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_utils/curl_utils.py +0 -0
  84. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_utils/deprecation.py +0 -0
  85. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_utils/display_utils.py +0 -0
  86. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_utils/docker_utils.py +0 -0
  87. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_utils/function_utils.py +0 -0
  88. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_utils/git_utils.py +0 -0
  89. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_utils/grpc_testing.py +0 -0
  90. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_utils/grpc_utils.py +0 -0
  91. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_utils/hash_utils.py +0 -0
  92. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_utils/http_utils.py +0 -0
  93. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_utils/idle_countdown.py +0 -0
  94. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_utils/jwt_utils.py +0 -0
  95. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_utils/logger.py +0 -0
  96. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_utils/mount_utils.py +0 -0
  97. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_utils/name_utils.py +0 -0
  98. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_utils/package_utils.py +0 -0
  99. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_utils/pattern_utils.py +0 -0
  100. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_utils/proxy_support.py +0 -0
  101. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_utils/rand_pb_testing.py +0 -0
  102. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_utils/sandbox_fs_utils.py +0 -0
  103. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_utils/shell_utils.py +0 -0
  104. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_utils/task_command_router_client.py +0 -0
  105. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_utils/time_utils.py +0 -0
  106. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_vendor/__init__.py +0 -0
  107. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_vendor/a2wsgi_wsgi.py +0 -0
  108. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_vendor/cloudpickle.py +0 -0
  109. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_vendor/tblib.py +0 -0
  110. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_vendor/version.py +0 -0
  111. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_watcher.py +0 -0
  112. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/_workspace.py +0 -0
  113. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/app.py +0 -0
  114. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/app.pyi +0 -0
  115. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/billing.py +0 -0
  116. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/billing.pyi +0 -0
  117. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/builder/2023.12.312.txt +0 -0
  118. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/builder/2023.12.txt +0 -0
  119. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/builder/2024.04.txt +0 -0
  120. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/builder/2024.10.txt +0 -0
  121. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/builder/2025.06.txt +0 -0
  122. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/builder/PREVIEW.txt +0 -0
  123. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/builder/README.md +0 -0
  124. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/builder/base-images.json +0 -0
  125. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/call_graph.py +0 -0
  126. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/cli/__init__.py +0 -0
  127. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/cli/_download.py +0 -0
  128. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/cli/_help.py +0 -0
  129. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/cli/_logs.py +0 -0
  130. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/cli/_stats.py +0 -0
  131. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/cli/_traceback.py +0 -0
  132. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/cli/app.py +0 -0
  133. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/cli/billing.py +0 -0
  134. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/cli/changelog.py +0 -0
  135. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/cli/config.py +0 -0
  136. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/cli/curl.py +0 -0
  137. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/cli/dashboard.py +0 -0
  138. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/cli/dict.py +0 -0
  139. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/cli/endpoint.py +0 -0
  140. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/cli/entry_point.py +0 -0
  141. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/cli/environment.py +0 -0
  142. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/cli/function.py +0 -0
  143. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/cli/image.py +0 -0
  144. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/cli/import_refs.py +0 -0
  145. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/cli/logo.py +0 -0
  146. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/cli/network_file_system.py +0 -0
  147. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/cli/profile.py +0 -0
  148. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/cli/queues.py +0 -0
  149. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/cli/run.py +0 -0
  150. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/cli/secret.py +0 -0
  151. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/cli/selector.py +0 -0
  152. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/cli/server.py +0 -0
  153. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/cli/skills.py +0 -0
  154. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/cli/token.py +0 -0
  155. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/cli/utils.py +0 -0
  156. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/cli/volume.py +0 -0
  157. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/cli/workspace.py +0 -0
  158. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/client.py +0 -0
  159. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/cloud_bucket_mount.py +0 -0
  160. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/cloud_bucket_mount.pyi +0 -0
  161. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/cls.py +0 -0
  162. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/cls.pyi +0 -0
  163. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/cluster.py +0 -0
  164. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/cluster.pyi +0 -0
  165. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/config.py +0 -0
  166. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/container_process.py +0 -0
  167. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/container_process.pyi +0 -0
  168. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/dict.py +0 -0
  169. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/dict.pyi +0 -0
  170. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/environments.py +0 -0
  171. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/environments.pyi +0 -0
  172. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/exception.py +0 -0
  173. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/experimental/_flash_container_entry.py +0 -0
  174. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/experimental/flash.py +0 -0
  175. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/experimental/flash.pyi +0 -0
  176. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/experimental/flash_server.py +0 -0
  177. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/experimental/flash_server.pyi +0 -0
  178. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/experimental/ipython.py +0 -0
  179. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/file_pattern_matcher.py +0 -0
  180. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/functions.py +0 -0
  181. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/image.py +0 -0
  182. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/image.pyi +0 -0
  183. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/io_streams.py +0 -0
  184. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/io_streams.pyi +0 -0
  185. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/mount.py +0 -0
  186. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/mount.pyi +0 -0
  187. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/network_file_system.py +0 -0
  188. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/network_file_system.pyi +0 -0
  189. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/object.py +0 -0
  190. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/object.pyi +0 -0
  191. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/output.py +0 -0
  192. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/parallel_map.py +0 -0
  193. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/parallel_map.pyi +0 -0
  194. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/partial_function.py +0 -0
  195. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/partial_function.pyi +0 -0
  196. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/proxy.py +0 -0
  197. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/proxy.pyi +0 -0
  198. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/py.typed +0 -0
  199. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/queue.py +0 -0
  200. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/queue.pyi +0 -0
  201. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/retries.py +0 -0
  202. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/runner.pyi +0 -0
  203. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/running_app.py +0 -0
  204. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/schedule.py +0 -0
  205. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/scheduler_placement.py +0 -0
  206. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/server.py +0 -0
  207. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/server.pyi +0 -0
  208. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/serving.py +0 -0
  209. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/serving.pyi +0 -0
  210. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/skills/modal/SKILL.md +0 -0
  211. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/snapshot.py +0 -0
  212. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/snapshot.pyi +0 -0
  213. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/stream_type.py +0 -0
  214. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/token_flow.py +0 -0
  215. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/token_flow.pyi +0 -0
  216. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/types.py +0 -0
  217. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/volume.py +0 -0
  218. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/volume.pyi +0 -0
  219. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/workspace.py +0 -0
  220. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal/workspace.pyi +0 -0
  221. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal.egg-info/dependency_links.txt +0 -0
  222. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal.egg-info/entry_points.txt +0 -0
  223. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal.egg-info/requires.txt +0 -0
  224. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal.egg-info/top_level.txt +0 -0
  225. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal_docs/__init__.py +0 -0
  226. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal_docs/gen_cli_docs.py +0 -0
  227. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal_docs/gen_cli_docs_main.py +0 -0
  228. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal_docs/gen_reference_docs.py +0 -0
  229. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal_docs/gen_reference_docs_main.py +0 -0
  230. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal_docs/mdmd/__init__.py +0 -0
  231. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal_docs/mdmd/mdmd.py +0 -0
  232. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal_docs/mdmd/signatures.py +0 -0
  233. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal_docs/mdmd/types.py +0 -0
  234. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal_docs/reference_intro.md +0 -0
  235. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal_proto/__init__.py +0 -0
  236. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal_proto/py.typed +0 -0
  237. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal_proto/task_command_router_grpc.py +0 -0
  238. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal_proto/task_command_router_pb2.py +0 -0
  239. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal_proto/task_command_router_pb2.pyi +0 -0
  240. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal_proto/task_command_router_pb2_grpc.py +0 -0
  241. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal_proto/task_command_router_pb2_grpc.pyi +0 -0
  242. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/modal_version/__main__.py +0 -0
  243. {modal-1.6.2.dev3 → modal-1.6.2.dev4}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.6.2.dev3
3
+ Version: 1.6.2.dev4
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License-Expression: Apache-2.0
@@ -819,8 +819,8 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
819
819
  raise InvalidError(
820
820
  f"`min_containers` ({min_containers}) cannot be greater than `max_containers` ({max_containers})"
821
821
  )
822
- if scaledown_window is not None and scaledown_window <= 0:
823
- raise InvalidError("`scaledown_window` must be > 0")
822
+ if scaledown_window is not None and not (2 <= scaledown_window <= 3600):
823
+ raise InvalidError("`scaledown_window` must be between 2 and 3600 (inclusive)")
824
824
 
825
825
  autoscaler_settings = api_pb2.AutoscalerSettings(
826
826
  min_containers=min_containers,
@@ -27,7 +27,8 @@ from modal.cli.utils import (
27
27
  )
28
28
  from modal.client import _Client
29
29
  from modal.exception import ConflictError, InvalidError
30
- from modal.sandbox import SandboxVersion, _container_exec, _get_sandbox_version, _Sandbox
30
+ from modal.sandbox._sandbox import SandboxVersion, _get_sandbox_version, _Sandbox
31
+ from modal.sandbox.sandbox import _container_exec
31
32
  from modal_proto import api_pb2
32
33
 
33
34
  from ._help import ModalGroup
@@ -17,7 +17,9 @@ from ..functions import Function
17
17
  from ..image import Image
18
18
  from ..mount import _Mount
19
19
  from ..runner import interactive_shell
20
- from ..sandbox import _MAIN_CONTAINER_NAME, Sandbox, SandboxVersion, _container_exec, _get_sandbox_version
20
+ from ..sandbox import Sandbox
21
+ from ..sandbox._sandbox import _MAIN_CONTAINER_NAME, SandboxVersion, _get_sandbox_version
22
+ from ..sandbox.sandbox import _container_exec
21
23
  from ..secret import Secret
22
24
  from ..stream_type import StreamType
23
25
  from ..types import SandboxRuntime
@@ -80,7 +80,7 @@ class _Client:
80
80
  server_url: str,
81
81
  client_type: int,
82
82
  credentials: typing.Optional[tuple[str, str]],
83
- version: str = "1.6.2.dev3",
83
+ version: str = "1.6.2.dev4",
84
84
  *,
85
85
  oauth_credentials: typing.Optional[_OAuthCredentials] = None,
86
86
  ):
@@ -290,7 +290,7 @@ class Client:
290
290
  server_url: str,
291
291
  client_type: int,
292
292
  credentials: typing.Optional[tuple[str, str]],
293
- version: str = "1.6.2.dev3",
293
+ version: str = "1.6.2.dev4",
294
294
  *,
295
295
  oauth_credentials: typing.Optional[_OAuthCredentials] = None,
296
296
  ):
@@ -93,6 +93,72 @@ def clustered(size: int, broadcast: bool = True, rdma: bool = False, fabric_size
93
93
  return wrapper
94
94
 
95
95
 
96
+ @dataclass
97
+ class ClusterReservationTask:
98
+ """A container running on a worker that belongs to a cluster reservation."""
99
+
100
+ task_id: str
101
+ cluster_rank: int
102
+ app_id: str
103
+ function_id: str
104
+
105
+
106
+ @dataclass
107
+ class ClusterReservation:
108
+ """Current state of reserved multi-node cluster capacity in a Workspace."""
109
+
110
+ name: str # Reservation name, as configured by Modal
111
+ gpu_type: str # e.g. "B300"
112
+ region: str
113
+ min_reserved_workers: int # Number of workers Modal has committed to keep reserved
114
+ reserved_workers: int # Healthy reserved workers currently present (active + idle)
115
+ active_workers: int # Reserved workers running this Workspace's containers
116
+ idle_workers: int # Reserved workers available for new clusters
117
+ unfulfilled_workers: int # max(0, min_reserved_workers - reserved_workers)
118
+ tasks: list[ClusterReservationTask] # Containers on reserved workers, ordered by cluster then rank
119
+
120
+
121
+ @synchronizer.create_blocking
122
+ async def list_cluster_reservations(*, client: _Client | None = None) -> list[ClusterReservation]:
123
+ """List reserved multi-node cluster capacity for the current Workspace.
124
+
125
+ Returns one entry per reservation Modal has configured for the Workspace, with how many of the
126
+ reserved workers are currently present, in use, idle or missing. Only Workspaces with reserved
127
+ cluster capacity (or explicitly allowlisted by Modal) may call this; others get a
128
+ `modal.exception.PermissionDeniedError`.
129
+
130
+ This interface is experimental. This information will continue to be available in the future,
131
+ but it may be accessed via a different interface, and the return value may have a different shape.
132
+ """
133
+ client = client or await _Client.from_env()
134
+
135
+ resp: api_pb2.ClusterReservationListResponse = await client._stub.ClusterReservationList(
136
+ api_pb2.ClusterReservationListRequest()
137
+ )
138
+ return [
139
+ ClusterReservation(
140
+ name=reservation.name,
141
+ gpu_type=reservation.gpu_type,
142
+ region=reservation.region,
143
+ min_reserved_workers=reservation.min_reserved_workers,
144
+ reserved_workers=reservation.reserved_workers,
145
+ active_workers=reservation.active_workers,
146
+ idle_workers=reservation.idle_workers,
147
+ unfulfilled_workers=reservation.unfulfilled_workers,
148
+ tasks=[
149
+ ClusterReservationTask(
150
+ task_id=task.task_id,
151
+ cluster_rank=task.cluster_rank,
152
+ app_id=task.app_id,
153
+ function_id=task.function_id,
154
+ )
155
+ for task in reservation.tasks
156
+ ],
157
+ )
158
+ for reservation in resp.reservations
159
+ ]
160
+
161
+
96
162
  @dataclass
97
163
  class AppInfo:
98
164
  app_id: str
@@ -613,7 +613,7 @@ class Function(
613
613
 
614
614
  _call_generator: ___call_generator_spec
615
615
 
616
- class __remote_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER]):
616
+ class __remote_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER]):
617
617
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> ReturnType_INNER:
618
618
  """Calls the function remotely, executing it with the given arguments and returning the execution's result.
619
619
 
@@ -638,7 +638,7 @@ class Function(
638
638
  """
639
639
  ...
640
640
 
641
- remote: __remote_spec[modal._functions.P, modal._functions.ReturnType]
641
+ remote: __remote_spec[modal._functions.ReturnType, modal._functions.P]
642
642
 
643
643
  class __remote_gen_spec(typing_extensions.Protocol):
644
644
  def __call__(self, /, *args, **kwargs) -> typing.Generator[typing.Any, None, None]:
@@ -688,7 +688,7 @@ class Function(
688
688
  """
689
689
  ...
690
690
 
691
- class ___experimental_spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER]):
691
+ class ___experimental_spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER]):
692
692
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
693
693
  """[Experimental] Calls the function with the given arguments, without waiting for the results.
694
694
 
@@ -721,7 +721,7 @@ class Function(
721
721
  """
722
722
  ...
723
723
 
724
- _experimental_spawn: ___experimental_spawn_spec[modal._functions.P, modal._functions.ReturnType]
724
+ _experimental_spawn: ___experimental_spawn_spec[modal._functions.ReturnType, modal._functions.P]
725
725
 
726
726
  class ___spawn_map_inner_spec(typing_extensions.Protocol[P_INNER]):
727
727
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> None: ...
@@ -729,7 +729,7 @@ class Function(
729
729
 
730
730
  _spawn_map_inner: ___spawn_map_inner_spec[modal._functions.P]
731
731
 
732
- class __spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER]):
732
+ class __spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER]):
733
733
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
734
734
  """Calls the function with the given arguments, without waiting for the results.
735
735
 
@@ -762,7 +762,7 @@ class Function(
762
762
  """
763
763
  ...
764
764
 
765
- spawn: __spawn_spec[modal._functions.P, modal._functions.ReturnType]
765
+ spawn: __spawn_spec[modal._functions.ReturnType, modal._functions.P]
766
766
 
767
767
  @property
768
768
  def _raw_f_(self) -> collections.abc.Callable[..., typing.Any]: ...
@@ -43,7 +43,7 @@ from .exception import (
43
43
  )
44
44
  from .output import OutputManager
45
45
  from .running_app import RunningApp, running_app_from_layout
46
- from .sandbox import _Sandbox
46
+ from .sandbox._sandbox import _Sandbox
47
47
  from .secret import _Secret
48
48
  from .stream_type import StreamType
49
49
 
@@ -0,0 +1,9 @@
1
+ # Copyright Modal Labs 2026
2
+ from ._sandbox import (
3
+ Probe as Probe,
4
+ )
5
+ from .sandbox import (
6
+ Sandbox as Sandbox,
7
+ SidecarContainer as SidecarContainer,
8
+ SidecarManager as SidecarManager,
9
+ )
@@ -23,31 +23,31 @@ from modal._supports_logs import LogsFilters, _LogQueryData
23
23
  from modal._tunnel import Tunnel
24
24
  from modal.cloud_bucket_mount import _CloudBucketMount, cloud_bucket_mounts_to_proto
25
25
  from modal.mount import _Mount
26
- from modal.secret import _local_secret_env, _resolvable_secrets
26
+ from modal.secret import _local_secret_env, _resolvable_secrets, _secret_sources
27
27
  from modal.volume import _Volume, _volume_to_mount_proto
28
28
  from modal_proto import api_pb2, task_command_router_pb2 as sr_pb2
29
29
 
30
- from ._image import _Image
31
- from ._load_context import LoadContext
32
- from ._object import _get_environment_name, _Object
33
- from ._outbound_policy import _OutboundPolicy, _validate_compatible_network_access
34
- from ._output.pty import get_pty_info
35
- from ._resolver import Resolver
36
- from ._resources import convert_fn_config_to_resources_config
37
- from ._utils.async_utils import TaskContext, synchronize_api, synchronizer
38
- from ._utils.deprecation import deprecation_warning
39
- from ._utils.grpc_utils import Retry, RetryTimeoutError
40
- from ._utils.mount_utils import (
30
+ from .._image import _Image
31
+ from .._load_context import LoadContext
32
+ from .._object import _get_environment_name, _Object
33
+ from .._outbound_policy import _OutboundPolicy, _validate_compatible_network_access
34
+ from .._output.pty import get_pty_info
35
+ from .._resolver import Resolver
36
+ from .._resources import convert_fn_config_to_resources_config
37
+ from .._utils.async_utils import TaskContext
38
+ from .._utils.deprecation import deprecation_warning
39
+ from .._utils.grpc_utils import Retry, RetryTimeoutError
40
+ from .._utils.mount_utils import (
41
41
  validate_network_file_systems,
42
42
  validate_volumes,
43
43
  validate_volumes_by_object_id,
44
44
  )
45
- from ._utils.name_utils import check_object_name
46
- from ._utils.task_command_router_client import TaskCommandRouterClient, _is_v2_task_id
47
- from .client import _Client
48
- from .config import config, logger
49
- from .container_process import _ContainerProcess
50
- from .exception import (
45
+ from .._utils.name_utils import check_object_name
46
+ from .._utils.task_command_router_client import TaskCommandRouterClient, _is_v2_task_id
47
+ from ..client import _Client
48
+ from ..config import config, logger
49
+ from ..container_process import _ContainerProcess
50
+ from ..exception import (
51
51
  ClientClosed,
52
52
  ConflictError,
53
53
  ExecutionError,
@@ -61,7 +61,7 @@ from .exception import (
61
61
  SnapshotCreationError,
62
62
  TimeoutError,
63
63
  )
64
- from .io_streams import (
64
+ from ..io_streams import (
65
65
  StreamReader,
66
66
  StreamWriter,
67
67
  _StreamReader,
@@ -71,13 +71,13 @@ from .io_streams import (
71
71
  _StreamWriterThroughCommandRouterSandboxParams,
72
72
  _StreamWriterThroughServerParams,
73
73
  )
74
- from .network_file_system import _NetworkFileSystem, network_file_system_mount_protos
75
- from .proxy import _Proxy
76
- from .sandbox_fs import _SandboxFilesystem
77
- from .secret import _Secret
78
- from .snapshot import _SandboxSnapshot
79
- from .stream_type import StreamType
80
- from .types import SandboxConnectCredentials, SandboxRuntime
74
+ from ..network_file_system import _NetworkFileSystem, network_file_system_mount_protos
75
+ from ..proxy import _Proxy
76
+ from ..sandbox_fs import _SandboxFilesystem
77
+ from ..secret import _Secret
78
+ from ..snapshot import _SandboxSnapshot
79
+ from ..stream_type import StreamType
80
+ from ..types import SandboxConnectCredentials, SandboxRuntime
81
81
 
82
82
  _default_image: _Image = _Image.debian_slim()
83
83
  _EXIT_SNAPSHOT_NOT_FOUND_ERROR_CODES = frozenset(
@@ -307,11 +307,11 @@ class DefaultSandboxNameOverride(str):
307
307
  """
308
308
 
309
309
  def __repr__(self) -> str:
310
- # NOTE: this must match the instance var name below in order for type stubs to work 😬
311
- return "_DEFAULT_SANDBOX_NAME_OVERRIDE"
310
+ # NOTE: this must match the qualified instance var name below in order for type stubs to work 😬
311
+ return "modal.sandbox._sandbox._DEFAULT_SANDBOX_NAME_OVERRIDE"
312
312
 
313
313
 
314
- _DEFAULT_SANDBOX_NAME_OVERRIDE = DefaultSandboxNameOverride()
314
+ _DEFAULT_SANDBOX_NAME_OVERRIDE: DefaultSandboxNameOverride = DefaultSandboxNameOverride()
315
315
 
316
316
 
317
317
  @dataclass(frozen=True)
@@ -386,7 +386,7 @@ def _resolve_app_id_and_client(
386
386
  client: "_Client | None",
387
387
  ) -> "tuple[str | None, _Client | None]":
388
388
  """Resolve the App id and client for Sandbox creation, validating that an App is available."""
389
- from .app import _App
389
+ from ..app import _App
390
390
 
391
391
  if app is not None:
392
392
  if app.app_id is None:
@@ -1116,9 +1116,6 @@ class _Sandbox(_Object, type_prefix="sb"):
1116
1116
  dep_tasks.append(resolver.load(proxy, load_context))
1117
1117
  dep_timings = await _gather_load_with_timings(dep_tasks) if dep_tasks else []
1118
1118
 
1119
- # `env` takes precedence over environment variables from secrets
1120
- env_dict = _local_secret_env(secrets) | ephemeral_env
1121
-
1122
1119
  validate_volumes_by_object_id(validated_volumes)
1123
1120
 
1124
1121
  volume_mounts = [_volume_to_mount_proto(path, volume) for path, volume in validated_volumes]
@@ -1165,7 +1162,7 @@ class _Sandbox(_Object, type_prefix="sb"):
1165
1162
  create_req = api_pb2.SandboxCreateV2Request(
1166
1163
  app_id=load_context.app_id,
1167
1164
  definition=definition,
1168
- ephemeral_secrets=api_pb2.StringMap(contents=env_dict) if env_dict else None,
1165
+ secret_sources=_secret_sources(secrets, ephemeral_env),
1169
1166
  tags=tag_protos,
1170
1167
  cloud_bucket_mount_credentials=cloud_bucket_credientials,
1171
1168
  )
@@ -2306,8 +2303,7 @@ class _Sandbox(_Object, type_prefix="sb"):
2306
2303
  secret_coros = [secret.hydrate(client=self._client) for secret in resolvable_secrets]
2307
2304
  await TaskContext.gather(*secret_coros)
2308
2305
 
2309
- env_dict = _local_secret_env(secrets)
2310
- env_dict |= {k: v for k, v in (env or {}).items() if v is not None}
2306
+ env_dict = {k: v for k, v in (env or {}).items() if v is not None}
2311
2307
 
2312
2308
  task_id = await self._get_task_id(raise_if_task_complete=True)
2313
2309
 
@@ -2324,8 +2320,7 @@ class _Sandbox(_Object, type_prefix="sb"):
2324
2320
  stderr=stderr,
2325
2321
  timeout=timeout,
2326
2322
  workdir=workdir,
2327
- secret_ids=[secret.object_id for secret in resolvable_secrets],
2328
- env=env_dict,
2323
+ secret_sources=_secret_sources(secrets, env_dict),
2329
2324
  text=text,
2330
2325
  bufsize=bufsize,
2331
2326
  runtime_debug=config.get("function_runtime_debug"),
@@ -2342,8 +2337,7 @@ class _Sandbox(_Object, type_prefix="sb"):
2342
2337
  stderr: StreamType = StreamType.PIPE,
2343
2338
  timeout: int | None = None,
2344
2339
  workdir: str | None = None,
2345
- secret_ids: Collection[str] | None = None,
2346
- env: dict[str, str] | None = None,
2340
+ secret_sources: Collection[api_pb2.SecretSource] | None = None,
2347
2341
  text: bool = True,
2348
2342
  bufsize: Literal[-1, 1] = -1,
2349
2343
  runtime_debug: bool = False,
@@ -2382,11 +2376,10 @@ class _Sandbox(_Object, type_prefix="sb"):
2382
2376
  stderr_config=stderr_config,
2383
2377
  timeout_secs=timeout,
2384
2378
  workdir=workdir,
2385
- secret_ids=secret_ids,
2379
+ secret_sources=secret_sources,
2386
2380
  pty_info=pty_info,
2387
2381
  runtime_debug=runtime_debug,
2388
2382
  container_id=container_id or "",
2389
- env=env or {},
2390
2383
  )
2391
2384
  _ = await command_router_client.exec_start(start_req)
2392
2385
 
@@ -3233,8 +3226,7 @@ class _SidecarManager:
3233
3226
  *(resolver.load(dependency, load_context) for dependency in dependencies if not dependency._is_hydrated)
3234
3227
  )
3235
3228
 
3236
- # `env` takes precedence over environment variables from secrets
3237
- env_dict = _local_secret_env(secrets) | (env or {})
3229
+ secret_sources = _secret_sources(secrets, env)
3238
3230
 
3239
3231
  # Validate that the same volume (by object_id) isn't mounted at multiple paths. This relies on
3240
3232
  # the volumes being hydrated above, since it compares object_ids.
@@ -3271,7 +3263,7 @@ class _SidecarManager:
3271
3263
  sandbox_id=self._sandbox.object_id,
3272
3264
  container_name=name,
3273
3265
  definition=definition,
3274
- ephemeral_secrets=api_pb2.StringMap(contents=env_dict) if env_dict else None,
3266
+ secret_sources=secret_sources,
3275
3267
  cloud_bucket_mount_credentials=cloud_bucket_credentials,
3276
3268
  )
3277
3269
  client = self._sandbox._client
@@ -3286,9 +3278,8 @@ class _SidecarManager:
3286
3278
  container_name=name,
3287
3279
  image_id=image.object_id,
3288
3280
  args=list(args),
3289
- env=env_dict,
3290
3281
  workdir=workdir or "",
3291
- secret_ids=[secret.object_id for secret in resolvable_secrets],
3282
+ secret_sources=secret_sources,
3292
3283
  volume_mounts=volume_mounts,
3293
3284
  network_access=network_access,
3294
3285
  pty_info=pty_info,
@@ -3328,7 +3319,6 @@ class _SidecarManager:
3328
3319
  ]
3329
3320
 
3330
3321
 
3331
- @synchronizer.create_blocking
3332
3322
  async def _container_exec(
3333
3323
  pty: bool,
3334
3324
  container_id: str = "",
@@ -3386,8 +3376,3 @@ async def _container_exec(
3386
3376
  stdout=StreamType.STDOUT,
3387
3377
  stderr=StreamType.STDOUT,
3388
3378
  ).wait()
3389
-
3390
-
3391
- SidecarContainer = synchronize_api(_SidecarContainer)
3392
- SidecarManager = synchronize_api(_SidecarManager)
3393
- Sandbox = synchronize_api(_Sandbox)
@@ -0,0 +1,9 @@
1
+ # Copyright Modal Labs 2026
2
+ from .._utils.async_utils import synchronize_api, synchronizer
3
+ from . import _sandbox
4
+
5
+ SidecarContainer = synchronize_api(_sandbox._SidecarContainer, target_module=__name__)
6
+ SidecarManager = synchronize_api(_sandbox._SidecarManager, target_module=__name__)
7
+ Sandbox = synchronize_api(_sandbox._Sandbox, target_module=__name__)
8
+
9
+ _container_exec = synchronizer.create_blocking(_sandbox._container_exec, "_container_exec", target_module=__name__)