modal 1.5.3.dev1__tar.gz → 1.5.3.dev3__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 (231) hide show
  1. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/PKG-INFO +1 -1
  2. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_functions.py +29 -3
  3. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_partial_function.py +14 -2
  4. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_utils/grpc_utils.py +1 -1
  5. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/app.py +10 -0
  6. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/client.pyi +2 -2
  7. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/cls.py +3 -0
  8. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/config.py +2 -1
  9. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/functions.pyi +23 -6
  10. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/sandbox.py +7 -3
  11. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/sandbox.pyi +20 -8
  12. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal.egg-info/PKG-INFO +1 -1
  13. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal_proto/api_grpc.py +16 -0
  14. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal_proto/api_pb2.py +956 -916
  15. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal_proto/api_pb2.pyi +88 -6
  16. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal_proto/api_pb2_grpc.py +33 -0
  17. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal_proto/api_pb2_grpc.pyi +10 -0
  18. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal_proto/modal_api_grpc.py +1 -0
  19. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal_version/__init__.py +1 -1
  20. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/LICENSE +0 -0
  21. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/README.md +0 -0
  22. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/__init__.py +0 -0
  23. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/__main__.py +0 -0
  24. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_billing.py +0 -0
  25. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_clustered_functions.py +0 -0
  26. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_clustered_functions.pyi +0 -0
  27. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_container_entrypoint.py +0 -0
  28. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_environments.py +0 -0
  29. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_function_variants.py +0 -0
  30. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_grpc_client.py +0 -0
  31. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_image.py +0 -0
  32. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_ipython.py +0 -0
  33. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_load_context.py +0 -0
  34. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_location.py +0 -0
  35. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_logs.py +0 -0
  36. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_object.py +0 -0
  37. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_output/__init__.py +0 -0
  38. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_output/manager.py +0 -0
  39. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_output/pty.py +0 -0
  40. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_output/rich.py +0 -0
  41. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_output/status.py +0 -0
  42. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_resolver.py +0 -0
  43. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_resources.py +0 -0
  44. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_runtime/__init__.py +0 -0
  45. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_runtime/asgi.py +0 -0
  46. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_runtime/container_io_manager.py +0 -0
  47. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_runtime/container_io_manager.pyi +0 -0
  48. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_runtime/execution_context.py +0 -0
  49. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_runtime/execution_context.pyi +0 -0
  50. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_runtime/gpu_memory_snapshot.py +0 -0
  51. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_runtime/task_lifecycle_manager.py +0 -0
  52. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_runtime/task_lifecycle_manager.pyi +0 -0
  53. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_runtime/telemetry.py +0 -0
  54. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_runtime/user_code_event_loop.py +0 -0
  55. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_runtime/user_code_imports.py +0 -0
  56. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_serialization.py +0 -0
  57. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_server.py +0 -0
  58. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_traceback.py +0 -0
  59. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_tunnel.py +0 -0
  60. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_tunnel.pyi +0 -0
  61. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_type_manager.py +0 -0
  62. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_utils/__init__.py +0 -0
  63. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_utils/app_utils.py +0 -0
  64. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_utils/async_utils.py +0 -0
  65. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_utils/auth_token_manager.py +0 -0
  66. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_utils/blob_utils.py +0 -0
  67. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_utils/browser_utils.py +0 -0
  68. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_utils/bytes_io_segment_payload.py +0 -0
  69. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_utils/curl_utils.py +0 -0
  70. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_utils/deprecation.py +0 -0
  71. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_utils/docker_utils.py +0 -0
  72. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_utils/function_utils.py +0 -0
  73. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_utils/git_utils.py +0 -0
  74. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_utils/grpc_testing.py +0 -0
  75. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_utils/hash_utils.py +0 -0
  76. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_utils/http_utils.py +0 -0
  77. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_utils/jwt_utils.py +0 -0
  78. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_utils/logger.py +0 -0
  79. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_utils/mount_utils.py +0 -0
  80. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_utils/name_utils.py +0 -0
  81. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_utils/package_utils.py +0 -0
  82. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_utils/pattern_utils.py +0 -0
  83. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_utils/proxy_support.py +0 -0
  84. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_utils/rand_pb_testing.py +0 -0
  85. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_utils/sandbox_fs_utils.py +0 -0
  86. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_utils/shell_utils.py +0 -0
  87. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_utils/task_command_router_client.py +0 -0
  88. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_utils/time_utils.py +0 -0
  89. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_vendor/__init__.py +0 -0
  90. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_vendor/a2wsgi_wsgi.py +0 -0
  91. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_vendor/cloudpickle.py +0 -0
  92. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_vendor/tblib.py +0 -0
  93. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_vendor/version.py +0 -0
  94. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_watcher.py +0 -0
  95. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/_workspace.py +0 -0
  96. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/app.pyi +0 -0
  97. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/billing.py +0 -0
  98. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/billing.pyi +0 -0
  99. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/builder/2023.12.312.txt +0 -0
  100. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/builder/2023.12.txt +0 -0
  101. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/builder/2024.04.txt +0 -0
  102. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/builder/2024.10.txt +0 -0
  103. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/builder/2025.06.txt +0 -0
  104. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/builder/PREVIEW.txt +0 -0
  105. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/builder/README.md +0 -0
  106. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/builder/base-images.json +0 -0
  107. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/call_graph.py +0 -0
  108. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/cli/__init__.py +0 -0
  109. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/cli/_download.py +0 -0
  110. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/cli/_help.py +0 -0
  111. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/cli/_traceback.py +0 -0
  112. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/cli/app.py +0 -0
  113. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/cli/billing.py +0 -0
  114. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/cli/bootstrap.py +0 -0
  115. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/cli/changelog.py +0 -0
  116. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/cli/cluster.py +0 -0
  117. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/cli/config.py +0 -0
  118. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/cli/container.py +0 -0
  119. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/cli/curl.py +0 -0
  120. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/cli/dashboard.py +0 -0
  121. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/cli/dict.py +0 -0
  122. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/cli/endpoint.py +0 -0
  123. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/cli/entry_point.py +0 -0
  124. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/cli/environment.py +0 -0
  125. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/cli/image.py +0 -0
  126. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/cli/import_refs.py +0 -0
  127. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/cli/launch.py +0 -0
  128. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/cli/logo.py +0 -0
  129. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/cli/network_file_system.py +0 -0
  130. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/cli/profile.py +0 -0
  131. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/cli/programs/__init__.py +0 -0
  132. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/cli/programs/run_jupyter.py +0 -0
  133. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/cli/programs/vscode.py +0 -0
  134. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/cli/queues.py +0 -0
  135. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/cli/run.py +0 -0
  136. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/cli/secret.py +0 -0
  137. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/cli/selector.py +0 -0
  138. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/cli/shell.py +0 -0
  139. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/cli/skills.py +0 -0
  140. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/cli/token.py +0 -0
  141. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/cli/utils.py +0 -0
  142. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/cli/volume.py +0 -0
  143. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/cli/workspace.py +0 -0
  144. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/client.py +0 -0
  145. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/cloud_bucket_mount.py +0 -0
  146. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/cloud_bucket_mount.pyi +0 -0
  147. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/cls.pyi +0 -0
  148. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/container_process.py +0 -0
  149. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/container_process.pyi +0 -0
  150. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/dict.py +0 -0
  151. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/dict.pyi +0 -0
  152. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/environments.py +0 -0
  153. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/environments.pyi +0 -0
  154. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/exception.py +0 -0
  155. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/experimental/__init__.py +0 -0
  156. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/experimental/flash.py +0 -0
  157. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/experimental/flash.pyi +0 -0
  158. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/experimental/ipython.py +0 -0
  159. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/file_io.py +0 -0
  160. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/file_io.pyi +0 -0
  161. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/file_pattern_matcher.py +0 -0
  162. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/functions.py +0 -0
  163. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/image.py +0 -0
  164. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/image.pyi +0 -0
  165. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/io_streams.py +0 -0
  166. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/io_streams.pyi +0 -0
  167. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/mount.py +0 -0
  168. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/mount.pyi +0 -0
  169. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/network_file_system.py +0 -0
  170. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/network_file_system.pyi +0 -0
  171. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/object.py +0 -0
  172. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/object.pyi +0 -0
  173. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/output.py +0 -0
  174. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/parallel_map.py +0 -0
  175. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/parallel_map.pyi +0 -0
  176. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/partial_function.py +0 -0
  177. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/partial_function.pyi +0 -0
  178. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/proxy.py +0 -0
  179. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/proxy.pyi +0 -0
  180. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/py.typed +0 -0
  181. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/queue.py +0 -0
  182. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/queue.pyi +0 -0
  183. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/retries.py +0 -0
  184. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/runner.py +0 -0
  185. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/runner.pyi +0 -0
  186. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/running_app.py +0 -0
  187. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/sandbox_fs.py +0 -0
  188. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/sandbox_fs.pyi +0 -0
  189. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/schedule.py +0 -0
  190. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/scheduler_placement.py +0 -0
  191. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/secret.py +0 -0
  192. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/secret.pyi +0 -0
  193. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/server.py +0 -0
  194. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/server.pyi +0 -0
  195. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/serving.py +0 -0
  196. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/serving.pyi +0 -0
  197. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/skills/modal/SKILL.md +0 -0
  198. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/snapshot.py +0 -0
  199. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/snapshot.pyi +0 -0
  200. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/stream_type.py +0 -0
  201. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/token_flow.py +0 -0
  202. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/token_flow.pyi +0 -0
  203. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/types.py +0 -0
  204. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/volume.py +0 -0
  205. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/volume.pyi +0 -0
  206. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/workspace.py +0 -0
  207. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal/workspace.pyi +0 -0
  208. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal.egg-info/SOURCES.txt +0 -0
  209. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal.egg-info/dependency_links.txt +0 -0
  210. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal.egg-info/entry_points.txt +0 -0
  211. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal.egg-info/requires.txt +0 -0
  212. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal.egg-info/top_level.txt +0 -0
  213. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal_docs/__init__.py +0 -0
  214. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal_docs/gen_cli_docs.py +0 -0
  215. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal_docs/gen_cli_docs_main.py +0 -0
  216. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal_docs/gen_reference_docs.py +0 -0
  217. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal_docs/gen_reference_docs_main.py +0 -0
  218. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal_docs/mdmd/__init__.py +0 -0
  219. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal_docs/mdmd/mdmd.py +0 -0
  220. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal_docs/mdmd/signatures.py +0 -0
  221. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal_docs/mdmd/types.py +0 -0
  222. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal_proto/__init__.py +0 -0
  223. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal_proto/py.typed +0 -0
  224. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal_proto/task_command_router_grpc.py +0 -0
  225. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal_proto/task_command_router_pb2.py +0 -0
  226. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal_proto/task_command_router_pb2.pyi +0 -0
  227. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal_proto/task_command_router_pb2_grpc.py +0 -0
  228. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal_proto/task_command_router_pb2_grpc.pyi +0 -0
  229. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/modal_version/__main__.py +0 -0
  230. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/pyproject.toml +0 -0
  231. {modal-1.5.3.dev1 → modal-1.5.3.dev3}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.5.3.dev1
3
+ Version: 1.5.3.dev3
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License-Expression: Apache-2.0
@@ -627,6 +627,7 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
627
627
  _metadata: api_pb2.FunctionHandleMetadata | None = None
628
628
  _options: _FunctionOptions
629
629
  _base_function: "_Function | None" = None
630
+ _app_id: str | None = None
630
631
 
631
632
  @staticmethod
632
633
  def from_local(
@@ -671,6 +672,7 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
671
672
  # Experimental: Clustered functions
672
673
  cluster_size: int | None = None,
673
674
  rdma: bool | None = None,
675
+ fabric_size: int | None = None,
674
676
  single_use_containers: bool = False,
675
677
  ephemeral_disk: int | None = None,
676
678
  include_source: bool = True,
@@ -1009,6 +1011,7 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
1009
1011
  mount_client_dependencies=mount_client_dependencies,
1010
1012
  # ---
1011
1013
  _experimental_group_size=cluster_size or 0, # Experimental: Clustered functions
1014
+ _experimental_fabric_size=fabric_size or 0, # Experimental: Clustered functions
1012
1015
  _experimental_concurrent_cancellations=True,
1013
1016
  # --- These are deprecated in favor of autoscaler_settings
1014
1017
  warm_pool_size=min_containers or 0,
@@ -1051,6 +1054,7 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
1051
1054
  method_definitions_set=function_definition.method_definitions_set,
1052
1055
  experimental_options=experimental_options or {},
1053
1056
  _experimental_group_size=function_definition._experimental_group_size,
1057
+ _experimental_fabric_size=function_definition._experimental_fabric_size,
1054
1058
  _experimental_buffer_containers=function_definition._experimental_buffer_containers,
1055
1059
  _experimental_custom_scaling=function_definition._experimental_custom_scaling,
1056
1060
  snapshot_debug=function_definition.snapshot_debug,
@@ -1400,6 +1404,7 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
1400
1404
  metadata.max_object_size_bytes if metadata.HasField("max_object_size_bytes") else MAX_OBJECT_SIZE_BYTES
1401
1405
  )
1402
1406
  self._experimental_flash_urls = metadata._experimental_flash_urls
1407
+ self._app_id = metadata.app_id or None
1403
1408
 
1404
1409
  # Invalidate the Function variant cache when we load new metadata, since the base Function handle
1405
1410
  # is now in sync with the server but any previously-cached variants may be stale.
@@ -1409,6 +1414,7 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
1409
1414
  # Overridden concrete implementation of base class method
1410
1415
  assert self._function_name, f"Function name must be set before metadata can be retrieved for {self}"
1411
1416
  return api_pb2.FunctionHandleMetadata(
1417
+ app_id=self._app_id or "",
1412
1418
  function_name=self._function_name,
1413
1419
  function_type=get_function_type(self._is_generator),
1414
1420
  web_url=self._web_url or "",
@@ -1670,6 +1676,8 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
1670
1676
  )
1671
1677
  fc: _FunctionCall[ReturnType] = _FunctionCall._new_hydrated(function_call_id, self.client, None)
1672
1678
  fc._num_inputs = num_inputs # set the cached value of num_inputs
1679
+ fc._app_id = self._app_id
1680
+ fc._function_id = self.object_id
1673
1681
  return fc
1674
1682
 
1675
1683
  async def _call_function(self, args, kwargs) -> ReturnType:
@@ -1881,6 +1889,8 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
1881
1889
  invocation.function_call_id, invocation.client, None
1882
1890
  )
1883
1891
  fc._is_generator = self._is_generator if self._is_generator else False
1892
+ fc._app_id = self._app_id
1893
+ fc._function_id = self.object_id
1884
1894
  return fc
1885
1895
 
1886
1896
  @synchronizer.no_input_translation
@@ -1917,6 +1927,8 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
1917
1927
  fc: _FunctionCall[ReturnType] = _FunctionCall._new_hydrated(
1918
1928
  invocation.function_call_id, invocation.client, None
1919
1929
  )
1930
+ fc._app_id = self._app_id
1931
+ fc._function_id = self.object_id
1920
1932
  return fc
1921
1933
 
1922
1934
  def get_raw_f(self) -> Callable[..., Any]:
@@ -1976,10 +1988,18 @@ class _FunctionCall(typing.Generic[ReturnType], _Object, type_prefix="fc"):
1976
1988
 
1977
1989
  _is_generator: bool = False
1978
1990
  _num_inputs: int | None = None
1991
+ _app_id: str | None = None
1992
+ _function_id: str | None = None
1979
1993
 
1980
1994
  def _invocation(self):
1981
1995
  return _Invocation(self.client.stub, self.object_id, self.client)
1982
1996
 
1997
+ async def _hydrate_from_id_metadata(self) -> None:
1998
+ """Hydrate metadata only when needed for FunctionCall fields."""
1999
+ request = api_pb2.FunctionCallFromIdRequest(function_call_id=self.object_id)
2000
+ resp = await self.client.stub.FunctionCallFromId(request)
2001
+ self._hydrate_metadata(resp)
2002
+
1983
2003
  @live_method
1984
2004
  async def num_inputs(self) -> int:
1985
2005
  """Get the number of inputs in the function call.
@@ -1988,9 +2008,8 @@ class _FunctionCall(typing.Generic[ReturnType], _Object, type_prefix="fc"):
1988
2008
  How many inputs this function call includes (e.g. `1` for `.spawn()`, more for `.spawn_map()`).
1989
2009
  """
1990
2010
  if self._num_inputs is None:
1991
- request = api_pb2.FunctionCallFromIdRequest(function_call_id=self.object_id)
1992
- resp = await self.client.stub.FunctionCallFromId(request)
1993
- self._num_inputs = resp.num_inputs # cached
2011
+ await self._hydrate_from_id_metadata()
2012
+ assert self._num_inputs is not None
1994
2013
  return self._num_inputs
1995
2014
 
1996
2015
  @live_method
@@ -2132,6 +2151,13 @@ class _FunctionCall(typing.Generic[ReturnType], _Object, type_prefix="fc"):
2132
2151
  )
2133
2152
  return typing.cast("modal.functions.FunctionCall[Any]", synchronizer._translate_out(impl_instance))
2134
2153
 
2154
+ def _hydrate_metadata(self, metadata: Message | None):
2155
+ # Overridden concrete implementation of base class method
2156
+ if isinstance(metadata, api_pb2.FunctionCallFromIdResponse):
2157
+ self._num_inputs = metadata.num_inputs
2158
+ self._app_id = metadata.metadata.app_id or None
2159
+ self._function_id = metadata.metadata.function_id or None
2160
+
2135
2161
  @staticmethod
2136
2162
  async def gather(*function_calls: "_FunctionCall[T]") -> typing.Sequence[T]:
2137
2163
  """Wait until all Modal FunctionCall objects have results before returning.
@@ -74,6 +74,7 @@ class _PartialFunctionParams:
74
74
  target_concurrent_inputs: int | None = None
75
75
  build_timeout: int | None = None
76
76
  rdma: bool | None = None
77
+ fabric_size: int | None = None
77
78
  http_config: api_pb2.HTTPConfig | None = None
78
79
 
79
80
  def update(self, other: "_PartialFunctionParams") -> None:
@@ -777,7 +778,7 @@ def _concurrent(
777
778
 
778
779
  # NOTE: clustered is currently exposed through modal.experimental, not the top-level namespace
779
780
  def _clustered(
780
- size: int, broadcast: bool = True, rdma: bool = False
781
+ size: int, broadcast: bool = True, rdma: bool = False, fabric_size: int | None = None
781
782
  ) -> Callable[
782
783
  [Callable[P, ReturnType] | _PartialFunction[P, ReturnType, ReturnType]],
783
784
  _PartialFunction[P, ReturnType, ReturnType],
@@ -791,6 +792,11 @@ def _clustered(
791
792
  If True, inputs will be sent simultaneously to each container. Otherwise,
792
793
  inputs will be sent only to the rank-0 container, which is responsible for
793
794
  delegating to the workers.
795
+ fabric_size: int | None = None
796
+ Experimental: constrains placement across GPU-memory fabrics. The cluster
797
+ is placed in co-fabric blocks of `fabric_size` containers, so every block
798
+ of `fabric_size` consecutive ranks shares a fabric (the scale-up domain)
799
+ and communicates over cross-node NVLink. Must evenly divide `size`.
794
800
  """
795
801
 
796
802
  assert broadcast, "broadcast=False has not been implemented yet!"
@@ -798,8 +804,14 @@ def _clustered(
798
804
  if size <= 0:
799
805
  raise ValueError("cluster size must be greater than 0")
800
806
 
807
+ if fabric_size is not None:
808
+ if not isinstance(fabric_size, int) or fabric_size <= 0:
809
+ raise ValueError("fabric_size must be a positive integer")
810
+ if size % fabric_size != 0:
811
+ raise ValueError(f"fabric_size must evenly divide the cluster size ({size} % {fabric_size} != 0)")
812
+
801
813
  flags = _PartialFunctionFlags.CLUSTERED
802
- params = _PartialFunctionParams(cluster_size=size, rdma=rdma)
814
+ params = _PartialFunctionParams(cluster_size=size, rdma=rdma, fabric_size=fabric_size)
803
815
 
804
816
  def wrapper(
805
817
  obj: _PartialFunction[P, ReturnType, ReturnType] | Callable[P, ReturnType],
@@ -325,7 +325,7 @@ def create_channel(
325
325
  async def create_channel_with_fallbacks(
326
326
  server_url: str,
327
327
  metadata: dict[str, str] = {},
328
- stagger_delay: float = 1.0,
328
+ stagger_delay: float = 3.0,
329
329
  ) -> grpclib.client.Channel:
330
330
  """Create a connected channel, supporting comma-separated fallback URLs.
331
331
 
@@ -920,6 +920,7 @@ class _App:
920
920
  i6pn_enabled = i6pn or (f.flags & _PartialFunctionFlags.CLUSTERED)
921
921
  cluster_size = f.params.cluster_size # Experimental: Clustered functions
922
922
  rdma = f.params.rdma
923
+ fabric_size = f.params.fabric_size
923
924
 
924
925
  info = FunctionInfo(f.raw_f, serialized=serialized, name_override=name)
925
926
  raw_f = f.raw_f
@@ -974,6 +975,7 @@ class _App:
974
975
 
975
976
  cluster_size = None # Experimental: Clustered functions
976
977
  rdma = None
978
+ fabric_size = None
977
979
  i6pn_enabled = i6pn
978
980
 
979
981
  if is_generator is None:
@@ -1016,6 +1018,7 @@ class _App:
1016
1018
  i6pn_enabled=i6pn_enabled,
1017
1019
  cluster_size=cluster_size, # Experimental: Clustered functions
1018
1020
  rdma=rdma,
1021
+ fabric_size=fabric_size, # Experimental: Clustered functions
1019
1022
  include_source=include_source if include_source is not None else local_state.include_source_default,
1020
1023
  experimental_options={k: str(v) for k, v in (experimental_options or {}).items()},
1021
1024
  restrict_output=_experimental_restrict_output,
@@ -1151,16 +1154,19 @@ class _App:
1151
1154
  if wrapped_cls.flags & _PartialFunctionFlags.CLUSTERED:
1152
1155
  cluster_size = wrapped_cls.params.cluster_size
1153
1156
  rdma = wrapped_cls.params.rdma
1157
+ fabric_size = wrapped_cls.params.fabric_size
1154
1158
 
1155
1159
  else:
1156
1160
  cluster_size = None
1157
1161
  rdma = None
1162
+ fabric_size = None
1158
1163
  else:
1159
1164
  user_cls = wrapped_cls
1160
1165
  max_concurrent_inputs = None
1161
1166
  target_concurrent_inputs = None
1162
1167
  cluster_size = None
1163
1168
  rdma = None
1169
+ fabric_size = None
1164
1170
  if not inspect.isclass(user_cls):
1165
1171
  raise TypeError("The @app.cls decorator must be used on a class.")
1166
1172
 
@@ -1246,6 +1252,7 @@ class _App:
1246
1252
  i6pn_enabled=i6pn_enabled,
1247
1253
  cluster_size=cluster_size,
1248
1254
  rdma=rdma,
1255
+ fabric_size=fabric_size,
1249
1256
  include_source=include_source if include_source is not None else local_state.include_source_default,
1250
1257
  experimental_options={k: str(v) for k, v in (experimental_options or {}).items()},
1251
1258
  restrict_output=_experimental_restrict_output,
@@ -1403,6 +1410,7 @@ class _App:
1403
1410
  # Extract the underlying class if wrapped in a _PartialFunction (e.g., from @modal.clustered())
1404
1411
  cluster_size = None
1405
1412
  rdma = None
1413
+ fabric_size = None
1406
1414
  user_cls = wrapped_user_cls
1407
1415
 
1408
1416
  if isinstance(wrapped_user_cls, _PartialFunction):
@@ -1410,6 +1418,7 @@ class _App:
1410
1418
  if wrapped_user_cls.flags & _PartialFunctionFlags.CLUSTERED:
1411
1419
  cluster_size = wrapped_user_cls.params.cluster_size
1412
1420
  rdma = wrapped_user_cls.params.rdma
1421
+ fabric_size = wrapped_user_cls.params.fabric_size
1413
1422
 
1414
1423
  local_state = self._local_state
1415
1424
 
@@ -1449,6 +1458,7 @@ class _App:
1449
1458
  i6pn_enabled=i6pn or (cluster_size is not None),
1450
1459
  cluster_size=cluster_size,
1451
1460
  rdma=rdma,
1461
+ fabric_size=fabric_size,
1452
1462
  include_source=include_source if include_source is not None else local_state.include_source_default,
1453
1463
  experimental_options={k: str(v) for k, v in (experimental_options or {}).items()},
1454
1464
  restrict_output=False,
@@ -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.5.3.dev1",
38
+ version: str = "1.5.3.dev3",
39
39
  ):
40
40
  """mdmd:hidden
41
41
  The Modal client object is not intended to be instantiated directly by users.
@@ -205,7 +205,7 @@ class Client:
205
205
  server_url: str,
206
206
  client_type: int,
207
207
  credentials: typing.Optional[tuple[str, str]],
208
- version: str = "1.5.3.dev1",
208
+ version: str = "1.5.3.dev3",
209
209
  ):
210
210
  """mdmd:hidden
211
211
  The Modal client object is not intended to be instantiated directly by users.
@@ -86,6 +86,8 @@ def _bind_instance_method(cls: "_Cls", service_function: _Function, method_name:
86
86
 
87
87
  method_metadata = service_function._method_handle_metadata[method_name]
88
88
  new_function._hydrate(service_function.object_id, service_function.client, method_metadata)
89
+ if not new_function._app_id:
90
+ new_function._app_id = service_function._app_id
89
91
 
90
92
  async def _load(fun: "_Function", resolver: Resolver, load_context: LoadContext, existing_object_id: str | None):
91
93
  # there is currently no actual loading logic executed to create each method on
@@ -426,6 +428,7 @@ class _Obj:
426
428
  )
427
429
  await resolver.load(method_function, load_context) # get the appropriate method handle (lazy)
428
430
  fun._hydrate_from_other(method_function)
431
+ fun._app_id = method_function._app_id
429
432
 
430
433
  # The reason we don't *always* use this lazy loader is because it precludes attribute access
431
434
  # on local classes.
@@ -106,7 +106,8 @@ from modal_proto import api_pb2
106
106
  from ._utils.logger import configure_logger
107
107
  from .exception import InvalidError, NotFoundError
108
108
 
109
- DEFAULT_SERVER_URL = "https://api.modal.com" # TODO(erikbern): add modal2.com
109
+ # By default, try api.modal.com and fail over to api.modal2.com
110
+ DEFAULT_SERVER_URL = "https://api.modal.com,https://api.modal2.com"
110
111
 
111
112
 
112
113
  # Locate config file and read it
@@ -58,6 +58,7 @@ class Function(
58
58
  _metadata: typing.Optional[modal_proto.api_pb2.FunctionHandleMetadata]
59
59
  _options: modal._function_variants._FunctionOptions
60
60
  _base_function: typing.Optional[Function]
61
+ _app_id: typing.Optional[str]
61
62
 
62
63
  def __init__(self, *args, **kwargs):
63
64
  """mdmd:hidden"""
@@ -109,6 +110,7 @@ class Function(
109
110
  i6pn_enabled: bool = False,
110
111
  cluster_size: typing.Optional[int] = None,
111
112
  rdma: typing.Optional[bool] = None,
113
+ fabric_size: typing.Optional[int] = None,
112
114
  single_use_containers: bool = False,
113
115
  ephemeral_disk: typing.Optional[int] = None,
114
116
  include_source: bool = True,
@@ -491,7 +493,7 @@ class Function(
491
493
 
492
494
  _call_generator: ___call_generator_spec
493
495
 
494
- class __remote_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER]):
496
+ class __remote_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER]):
495
497
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> ReturnType_INNER:
496
498
  """Calls the function remotely, executing it with the given arguments and returning the execution's result.
497
499
 
@@ -516,7 +518,7 @@ class Function(
516
518
  """
517
519
  ...
518
520
 
519
- remote: __remote_spec[modal._functions.P, modal._functions.ReturnType]
521
+ remote: __remote_spec[modal._functions.ReturnType, modal._functions.P]
520
522
 
521
523
  class __remote_gen_spec(typing_extensions.Protocol):
522
524
  def __call__(self, /, *args, **kwargs) -> typing.Generator[typing.Any, None, None]:
@@ -566,7 +568,7 @@ class Function(
566
568
  """
567
569
  ...
568
570
 
569
- class ___experimental_spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER]):
571
+ class ___experimental_spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER]):
570
572
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
571
573
  """[Experimental] Calls the function with the given arguments, without waiting for the results.
572
574
 
@@ -599,7 +601,7 @@ class Function(
599
601
  """
600
602
  ...
601
603
 
602
- _experimental_spawn: ___experimental_spawn_spec[modal._functions.P, modal._functions.ReturnType]
604
+ _experimental_spawn: ___experimental_spawn_spec[modal._functions.ReturnType, modal._functions.P]
603
605
 
604
606
  class ___spawn_map_inner_spec(typing_extensions.Protocol[P_INNER]):
605
607
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> None: ...
@@ -607,7 +609,7 @@ class Function(
607
609
 
608
610
  _spawn_map_inner: ___spawn_map_inner_spec[modal._functions.P]
609
611
 
610
- class __spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER]):
612
+ class __spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER]):
611
613
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
612
614
  """Calls the function with the given arguments, without waiting for the results.
613
615
 
@@ -640,7 +642,7 @@ class Function(
640
642
  """
641
643
  ...
642
644
 
643
- spawn: __spawn_spec[modal._functions.P, modal._functions.ReturnType]
645
+ spawn: __spawn_spec[modal._functions.ReturnType, modal._functions.P]
644
646
 
645
647
  def get_raw_f(self) -> collections.abc.Callable[..., typing.Any]:
646
648
  """Return the inner Python object wrapped by this Modal Function.
@@ -891,6 +893,8 @@ class FunctionCall(typing.Generic[modal._functions.ReturnType], modal.object.Obj
891
893
 
892
894
  _is_generator: bool
893
895
  _num_inputs: typing.Optional[int]
896
+ _app_id: typing.Optional[str]
897
+ _function_id: typing.Optional[str]
894
898
 
895
899
  def __init__(self, *args, **kwargs):
896
900
  """mdmd:hidden"""
@@ -898,6 +902,17 @@ class FunctionCall(typing.Generic[modal._functions.ReturnType], modal.object.Obj
898
902
 
899
903
  def _invocation(self): ...
900
904
 
905
+ class ___hydrate_from_id_metadata_spec(typing_extensions.Protocol):
906
+ def __call__(self, /) -> None:
907
+ """Hydrate metadata only when needed for FunctionCall fields."""
908
+ ...
909
+
910
+ async def aio(self, /) -> None:
911
+ """Hydrate metadata only when needed for FunctionCall fields."""
912
+ ...
913
+
914
+ _hydrate_from_id_metadata: ___hydrate_from_id_metadata_spec
915
+
901
916
  class __num_inputs_spec(typing_extensions.Protocol):
902
917
  def __call__(self, /) -> int:
903
918
  """Get the number of inputs in the function call.
@@ -1114,6 +1129,8 @@ class FunctionCall(typing.Generic[modal._functions.ReturnType], modal.object.Obj
1114
1129
 
1115
1130
  from_id: typing.ClassVar[__from_id_spec]
1116
1131
 
1132
+ def _hydrate_metadata(self, metadata: typing.Optional[google.protobuf.message.Message]): ...
1133
+
1117
1134
  class __gather_spec(typing_extensions.Protocol):
1118
1135
  def __call__(self, /, *function_calls: FunctionCall[modal._functions.T]) -> typing.Sequence[modal._functions.T]:
1119
1136
  """Wait until all Modal FunctionCall objects have results before returning.
@@ -349,7 +349,7 @@ class _Sandbox(_Object, type_prefix="sb"):
349
349
  gpu: str | None = None,
350
350
  cloud: str | None = None,
351
351
  region: str | Sequence[str] | None = None,
352
- cpu: float | None = None,
352
+ cpu: float | tuple[float, float] | None = None,
353
353
  memory: int | tuple[int, int] | None = None,
354
354
  mounts: Sequence[_Mount] = (),
355
355
  network_file_systems: dict[str | os.PathLike, _NetworkFileSystem] = {},
@@ -823,8 +823,8 @@ class _Sandbox(_Object, type_prefix="sb"):
823
823
  timeout: int = 300,
824
824
  idle_timeout: int | None = None,
825
825
  workdir: str | None = None,
826
- cpu: float | None = None,
827
- memory: int | None = None,
826
+ cpu: float | tuple[float, float] | None = None,
827
+ memory: int | tuple[int, int] | None = None,
828
828
  cloud: str | None = None,
829
829
  region: str | Sequence[str] | None = None,
830
830
  block_network: bool = False,
@@ -852,6 +852,10 @@ class _Sandbox(_Object, type_prefix="sb"):
852
852
  `secret=...` or `oidc_auth_role_arn`), OIDC identity tokens, proxies, and
853
853
  filesystem snapshots.
854
854
 
855
+ `cpu` and `memory` accept either a scalar request or a `(request, limit)`
856
+ tuple that additionally sets a hard limit (fractional CPU cores; memory
857
+ in MiB), matching `Sandbox.create()`.
858
+
855
859
  Features like memory snapshots, network file systems, GPUs, and custom
856
860
  domains are not supported.
857
861
 
@@ -165,7 +165,7 @@ class _Sandbox(modal._object._Object):
165
165
  gpu: typing.Optional[str] = None,
166
166
  cloud: typing.Optional[str] = None,
167
167
  region: typing.Union[str, collections.abc.Sequence[str], None] = None,
168
- cpu: typing.Optional[float] = None,
168
+ cpu: typing.Union[float, tuple[float, float], None] = None,
169
169
  memory: typing.Union[int, tuple[int, int], None] = None,
170
170
  mounts: collections.abc.Sequence[modal.mount._Mount] = (),
171
171
  network_file_systems: dict[typing.Union[str, os.PathLike], modal.network_file_system._NetworkFileSystem] = {},
@@ -368,8 +368,8 @@ class _Sandbox(modal._object._Object):
368
368
  timeout: int = 300,
369
369
  idle_timeout: typing.Optional[int] = None,
370
370
  workdir: typing.Optional[str] = None,
371
- cpu: typing.Optional[float] = None,
372
- memory: typing.Optional[int] = None,
371
+ cpu: typing.Union[float, tuple[float, float], None] = None,
372
+ memory: typing.Union[int, tuple[int, int], None] = None,
373
373
  cloud: typing.Optional[str] = None,
374
374
  region: typing.Union[str, collections.abc.Sequence[str], None] = None,
375
375
  block_network: bool = False,
@@ -400,6 +400,10 @@ class _Sandbox(modal._object._Object):
400
400
  `secret=...` or `oidc_auth_role_arn`), OIDC identity tokens, proxies, and
401
401
  filesystem snapshots.
402
402
 
403
+ `cpu` and `memory` accept either a scalar request or a `(request, limit)`
404
+ tuple that additionally sets a hard limit (fractional CPU cores; memory
405
+ in MiB), matching `Sandbox.create()`.
406
+
403
407
  Features like memory snapshots, network file systems, GPUs, and custom
404
408
  domains are not supported.
405
409
 
@@ -1337,7 +1341,7 @@ class Sandbox(modal.object.Object):
1337
1341
  gpu: typing.Optional[str] = None,
1338
1342
  cloud: typing.Optional[str] = None,
1339
1343
  region: typing.Union[str, collections.abc.Sequence[str], None] = None,
1340
- cpu: typing.Optional[float] = None,
1344
+ cpu: typing.Union[float, tuple[float, float], None] = None,
1341
1345
  memory: typing.Union[int, tuple[int, int], None] = None,
1342
1346
  mounts: collections.abc.Sequence[modal.mount.Mount] = (),
1343
1347
  network_file_systems: dict[typing.Union[str, os.PathLike], modal.network_file_system.NetworkFileSystem] = {},
@@ -1721,8 +1725,8 @@ class Sandbox(modal.object.Object):
1721
1725
  timeout: int = 300,
1722
1726
  idle_timeout: typing.Optional[int] = None,
1723
1727
  workdir: typing.Optional[str] = None,
1724
- cpu: typing.Optional[float] = None,
1725
- memory: typing.Optional[int] = None,
1728
+ cpu: typing.Union[float, tuple[float, float], None] = None,
1729
+ memory: typing.Union[int, tuple[int, int], None] = None,
1726
1730
  cloud: typing.Optional[str] = None,
1727
1731
  region: typing.Union[str, collections.abc.Sequence[str], None] = None,
1728
1732
  block_network: bool = False,
@@ -1753,6 +1757,10 @@ class Sandbox(modal.object.Object):
1753
1757
  `secret=...` or `oidc_auth_role_arn`), OIDC identity tokens, proxies, and
1754
1758
  filesystem snapshots.
1755
1759
 
1760
+ `cpu` and `memory` accept either a scalar request or a `(request, limit)`
1761
+ tuple that additionally sets a hard limit (fractional CPU cores; memory
1762
+ in MiB), matching `Sandbox.create()`.
1763
+
1756
1764
  Features like memory snapshots, network file systems, GPUs, and custom
1757
1765
  domains are not supported.
1758
1766
 
@@ -1783,8 +1791,8 @@ class Sandbox(modal.object.Object):
1783
1791
  timeout: int = 300,
1784
1792
  idle_timeout: typing.Optional[int] = None,
1785
1793
  workdir: typing.Optional[str] = None,
1786
- cpu: typing.Optional[float] = None,
1787
- memory: typing.Optional[int] = None,
1794
+ cpu: typing.Union[float, tuple[float, float], None] = None,
1795
+ memory: typing.Union[int, tuple[int, int], None] = None,
1788
1796
  cloud: typing.Optional[str] = None,
1789
1797
  region: typing.Union[str, collections.abc.Sequence[str], None] = None,
1790
1798
  block_network: bool = False,
@@ -1815,6 +1823,10 @@ class Sandbox(modal.object.Object):
1815
1823
  `secret=...` or `oidc_auth_role_arn`), OIDC identity tokens, proxies, and
1816
1824
  filesystem snapshots.
1817
1825
 
1826
+ `cpu` and `memory` accept either a scalar request or a `(request, limit)`
1827
+ tuple that additionally sets a hard limit (fractional CPU cores; memory
1828
+ in MiB), matching `Sandbox.create()`.
1829
+
1818
1830
  Features like memory snapshots, network file systems, GPUs, and custom
1819
1831
  domains are not supported.
1820
1832
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.5.3.dev1
3
+ Version: 1.5.3.dev3
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License-Expression: Apache-2.0
@@ -639,6 +639,10 @@ class ModalClientBase(abc.ABC):
639
639
  async def SandboxRestore(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.SandboxRestoreRequest, modal_proto.api_pb2.SandboxRestoreResponse]') -> None:
640
640
  pass
641
641
 
642
+ @abc.abstractmethod
643
+ async def SandboxSetName(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.SandboxSetNameRequest, modal_proto.api_pb2.SandboxSetNameResponse]') -> None:
644
+ pass
645
+
642
646
  @abc.abstractmethod
643
647
  async def SandboxSnapshot(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.SandboxSnapshotRequest, modal_proto.api_pb2.SandboxSnapshotResponse]') -> None:
644
648
  pass
@@ -1871,6 +1875,12 @@ class ModalClientBase(abc.ABC):
1871
1875
  modal_proto.api_pb2.SandboxRestoreRequest,
1872
1876
  modal_proto.api_pb2.SandboxRestoreResponse,
1873
1877
  ),
1878
+ '/modal.client.ModalClient/SandboxSetName': grpclib.const.Handler(
1879
+ self.SandboxSetName,
1880
+ grpclib.const.Cardinality.UNARY_UNARY,
1881
+ modal_proto.api_pb2.SandboxSetNameRequest,
1882
+ modal_proto.api_pb2.SandboxSetNameResponse,
1883
+ ),
1874
1884
  '/modal.client.ModalClient/SandboxSnapshot': grpclib.const.Handler(
1875
1885
  self.SandboxSnapshot,
1876
1886
  grpclib.const.Cardinality.UNARY_UNARY,
@@ -3257,6 +3267,12 @@ class ModalClientStub:
3257
3267
  modal_proto.api_pb2.SandboxRestoreRequest,
3258
3268
  modal_proto.api_pb2.SandboxRestoreResponse,
3259
3269
  )
3270
+ self.SandboxSetName = grpclib.client.UnaryUnaryMethod(
3271
+ channel,
3272
+ '/modal.client.ModalClient/SandboxSetName',
3273
+ modal_proto.api_pb2.SandboxSetNameRequest,
3274
+ modal_proto.api_pb2.SandboxSetNameResponse,
3275
+ )
3260
3276
  self.SandboxSnapshot = grpclib.client.UnaryUnaryMethod(
3261
3277
  channel,
3262
3278
  '/modal.client.ModalClient/SandboxSnapshot',