modAL 1.5.3__tar.gz → 1.5.3.dev0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (237) hide show
  1. {modal-1.5.3 → modal-1.5.3.dev0}/PKG-INFO +1 -1
  2. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_clustered_functions.py +0 -11
  3. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_clustered_functions.pyi +2 -6
  4. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_container_entrypoint.py +4 -2
  5. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_environments.py +81 -155
  6. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_function_variants.py +1 -1
  7. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_functions.py +21 -90
  8. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_grpc_client.py +1 -1
  9. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_object.py +4 -5
  10. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_output/rich.py +3 -3
  11. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_partial_function.py +3 -15
  12. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_resources.py +4 -4
  13. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_runtime/container_io_manager.py +30 -6
  14. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_runtime/container_io_manager.pyi +16 -5
  15. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_runtime/user_code_imports.py +1 -2
  16. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_server.py +1 -21
  17. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_traceback.py +1 -1
  18. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_utils/async_utils.py +0 -5
  19. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_utils/blob_utils.py +0 -1
  20. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_utils/bytes_io_segment_payload.py +1 -2
  21. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_utils/grpc_utils.py +1 -1
  22. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_utils/pattern_utils.py +2 -2
  23. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_utils/task_command_router_client.py +3 -132
  24. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_utils/time_utils.py +14 -106
  25. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_workspace.py +16 -78
  26. {modal-1.5.3 → modal-1.5.3.dev0}/modal/app.py +3 -15
  27. {modal-1.5.3 → modal-1.5.3.dev0}/modal/app.pyi +4 -8
  28. {modal-1.5.3 → modal-1.5.3.dev0}/modal/cli/billing.py +17 -121
  29. {modal-1.5.3 → modal-1.5.3.dev0}/modal/cli/cluster.py +1 -1
  30. {modal-1.5.3 → modal-1.5.3.dev0}/modal/cli/config.py +1 -1
  31. {modal-1.5.3 → modal-1.5.3.dev0}/modal/cli/dashboard.py +1 -1
  32. {modal-1.5.3 → modal-1.5.3.dev0}/modal/cli/endpoint.py +3 -23
  33. {modal-1.5.3 → modal-1.5.3.dev0}/modal/cli/environment.py +45 -206
  34. {modal-1.5.3 → modal-1.5.3.dev0}/modal/cli/launch.py +1 -1
  35. {modal-1.5.3 → modal-1.5.3.dev0}/modal/cli/network_file_system.py +1 -1
  36. {modal-1.5.3 → modal-1.5.3.dev0}/modal/cli/profile.py +3 -3
  37. {modal-1.5.3 → modal-1.5.3.dev0}/modal/cli/shell.py +4 -23
  38. {modal-1.5.3 → modal-1.5.3.dev0}/modal/client.py +8 -14
  39. {modal-1.5.3 → modal-1.5.3.dev0}/modal/client.pyi +21 -15
  40. {modal-1.5.3 → modal-1.5.3.dev0}/modal/cloud_bucket_mount.py +5 -18
  41. {modal-1.5.3 → modal-1.5.3.dev0}/modal/cloud_bucket_mount.pyi +2 -2
  42. {modal-1.5.3 → modal-1.5.3.dev0}/modal/cls.py +2 -5
  43. {modal-1.5.3 → modal-1.5.3.dev0}/modal/cls.pyi +4 -4
  44. {modal-1.5.3 → modal-1.5.3.dev0}/modal/config.py +1 -30
  45. {modal-1.5.3 → modal-1.5.3.dev0}/modal/container_process.py +1 -13
  46. {modal-1.5.3 → modal-1.5.3.dev0}/modal/container_process.pyi +0 -27
  47. {modal-1.5.3 → modal-1.5.3.dev0}/modal/environments.py +0 -3
  48. {modal-1.5.3 → modal-1.5.3.dev0}/modal/environments.pyi +66 -152
  49. {modal-1.5.3 → modal-1.5.3.dev0}/modal/exception.py +1 -5
  50. {modal-1.5.3 → modal-1.5.3.dev0}/modal/experimental/__init__.py +1 -11
  51. {modal-1.5.3 → modal-1.5.3.dev0}/modal/file_pattern_matcher.py +1 -1
  52. {modal-1.5.3 → modal-1.5.3.dev0}/modal/functions.pyi +24 -85
  53. {modal-1.5.3 → modal-1.5.3.dev0}/modal/mount.py +31 -89
  54. {modal-1.5.3 → modal-1.5.3.dev0}/modal/mount.pyi +6 -18
  55. {modal-1.5.3 → modal-1.5.3.dev0}/modal/partial_function.pyi +1 -1
  56. {modal-1.5.3 → modal-1.5.3.dev0}/modal/runner.py +9 -31
  57. {modal-1.5.3 → modal-1.5.3.dev0}/modal/runner.pyi +1 -8
  58. {modal-1.5.3 → modal-1.5.3.dev0}/modal/sandbox.py +61 -239
  59. {modal-1.5.3 → modal-1.5.3.dev0}/modal/sandbox.pyi +46 -251
  60. {modal-1.5.3 → modal-1.5.3.dev0}/modal/sandbox_fs.py +82 -33
  61. {modal-1.5.3 → modal-1.5.3.dev0}/modal/sandbox_fs.pyi +6 -26
  62. {modal-1.5.3 → modal-1.5.3.dev0}/modal/schedule.py +1 -1
  63. {modal-1.5.3 → modal-1.5.3.dev0}/modal/secret.py +2 -11
  64. {modal-1.5.3 → modal-1.5.3.dev0}/modal/secret.pyi +0 -18
  65. {modal-1.5.3 → modal-1.5.3.dev0}/modal/server.pyi +1 -24
  66. {modal-1.5.3 → modal-1.5.3.dev0}/modal/serving.py +3 -3
  67. {modal-1.5.3 → modal-1.5.3.dev0}/modal/snapshot.py +1 -17
  68. {modal-1.5.3 → modal-1.5.3.dev0}/modal/snapshot.pyi +0 -22
  69. {modal-1.5.3 → modal-1.5.3.dev0}/modal/types.py +1 -81
  70. {modal-1.5.3 → modal-1.5.3.dev0}/modal/workspace.pyi +20 -95
  71. {modal-1.5.3 → modal-1.5.3.dev0}/modal.egg-info/PKG-INFO +1 -1
  72. {modal-1.5.3 → modal-1.5.3.dev0}/modal.egg-info/SOURCES.txt +0 -5
  73. modal-1.5.3.dev0/modal_docs/gen_reference_docs.py +361 -0
  74. {modal-1.5.3 → modal-1.5.3.dev0}/modal_docs/mdmd/mdmd.py +46 -67
  75. {modal-1.5.3 → modal-1.5.3.dev0}/modal_docs/mdmd/types.py +0 -1
  76. {modal-1.5.3 → modal-1.5.3.dev0}/modal_proto/api_grpc.py +0 -48
  77. {modal-1.5.3 → modal-1.5.3.dev0}/modal_proto/api_pb2.py +1135 -1276
  78. {modal-1.5.3 → modal-1.5.3.dev0}/modal_proto/api_pb2.pyi +51 -314
  79. {modal-1.5.3 → modal-1.5.3.dev0}/modal_proto/api_pb2_grpc.py +0 -99
  80. {modal-1.5.3 → modal-1.5.3.dev0}/modal_proto/api_pb2_grpc.pyi +0 -30
  81. {modal-1.5.3 → modal-1.5.3.dev0}/modal_proto/modal_api_grpc.py +0 -3
  82. {modal-1.5.3 → modal-1.5.3.dev0}/modal_proto/task_command_router_grpc.py +0 -16
  83. {modal-1.5.3 → modal-1.5.3.dev0}/modal_proto/task_command_router_pb2.py +88 -108
  84. {modal-1.5.3 → modal-1.5.3.dev0}/modal_proto/task_command_router_pb2.pyi +2 -47
  85. {modal-1.5.3 → modal-1.5.3.dev0}/modal_proto/task_command_router_pb2_grpc.py +0 -37
  86. {modal-1.5.3 → modal-1.5.3.dev0}/modal_proto/task_command_router_pb2_grpc.pyi +0 -20
  87. {modal-1.5.3 → modal-1.5.3.dev0}/modal_version/__init__.py +1 -1
  88. {modal-1.5.3 → modal-1.5.3.dev0}/pyproject.toml +2 -49
  89. modal-1.5.3/modal/_logs_manager.py +0 -674
  90. modal-1.5.3/modal/_logs_manager.pyi +0 -1063
  91. modal-1.5.3/modal/_supports_logs.py +0 -32
  92. modal-1.5.3/modal/_utils/display_utils.py +0 -15
  93. modal-1.5.3/modal_docs/gen_reference_docs.py +0 -167
  94. modal-1.5.3/modal_docs/reference_intro.md +0 -115
  95. {modal-1.5.3 → modal-1.5.3.dev0}/LICENSE +0 -0
  96. {modal-1.5.3 → modal-1.5.3.dev0}/README.md +0 -0
  97. {modal-1.5.3 → modal-1.5.3.dev0}/modal/__init__.py +0 -0
  98. {modal-1.5.3 → modal-1.5.3.dev0}/modal/__main__.py +0 -0
  99. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_billing.py +0 -0
  100. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_image.py +0 -0
  101. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_ipython.py +0 -0
  102. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_load_context.py +0 -0
  103. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_location.py +0 -0
  104. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_logs.py +0 -0
  105. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_output/__init__.py +0 -0
  106. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_output/manager.py +0 -0
  107. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_output/pty.py +0 -0
  108. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_output/status.py +0 -0
  109. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_resolver.py +0 -0
  110. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_runtime/__init__.py +0 -0
  111. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_runtime/asgi.py +0 -0
  112. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_runtime/execution_context.py +0 -0
  113. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_runtime/execution_context.pyi +0 -0
  114. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_runtime/gpu_memory_snapshot.py +0 -0
  115. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_runtime/task_lifecycle_manager.py +0 -0
  116. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_runtime/task_lifecycle_manager.pyi +0 -0
  117. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_runtime/telemetry.py +0 -0
  118. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_runtime/user_code_event_loop.py +0 -0
  119. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_serialization.py +0 -0
  120. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_tunnel.py +0 -0
  121. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_tunnel.pyi +0 -0
  122. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_type_manager.py +0 -0
  123. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_utils/__init__.py +0 -0
  124. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_utils/app_utils.py +0 -0
  125. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_utils/auth_token_manager.py +0 -0
  126. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_utils/browser_utils.py +0 -0
  127. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_utils/curl_utils.py +0 -0
  128. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_utils/deprecation.py +0 -0
  129. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_utils/docker_utils.py +0 -0
  130. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_utils/function_utils.py +0 -0
  131. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_utils/git_utils.py +0 -0
  132. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_utils/grpc_testing.py +0 -0
  133. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_utils/hash_utils.py +0 -0
  134. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_utils/http_utils.py +0 -0
  135. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_utils/jwt_utils.py +0 -0
  136. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_utils/logger.py +0 -0
  137. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_utils/mount_utils.py +0 -0
  138. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_utils/name_utils.py +0 -0
  139. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_utils/package_utils.py +0 -0
  140. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_utils/proxy_support.py +0 -0
  141. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_utils/rand_pb_testing.py +0 -0
  142. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_utils/sandbox_fs_utils.py +0 -0
  143. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_utils/shell_utils.py +0 -0
  144. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_vendor/__init__.py +0 -0
  145. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_vendor/a2wsgi_wsgi.py +0 -0
  146. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_vendor/cloudpickle.py +0 -0
  147. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_vendor/tblib.py +0 -0
  148. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_vendor/version.py +0 -0
  149. {modal-1.5.3 → modal-1.5.3.dev0}/modal/_watcher.py +0 -0
  150. {modal-1.5.3 → modal-1.5.3.dev0}/modal/billing.py +0 -0
  151. {modal-1.5.3 → modal-1.5.3.dev0}/modal/billing.pyi +0 -0
  152. {modal-1.5.3 → modal-1.5.3.dev0}/modal/builder/2023.12.312.txt +0 -0
  153. {modal-1.5.3 → modal-1.5.3.dev0}/modal/builder/2023.12.txt +0 -0
  154. {modal-1.5.3 → modal-1.5.3.dev0}/modal/builder/2024.04.txt +0 -0
  155. {modal-1.5.3 → modal-1.5.3.dev0}/modal/builder/2024.10.txt +0 -0
  156. {modal-1.5.3 → modal-1.5.3.dev0}/modal/builder/2025.06.txt +0 -0
  157. {modal-1.5.3 → modal-1.5.3.dev0}/modal/builder/PREVIEW.txt +0 -0
  158. {modal-1.5.3 → modal-1.5.3.dev0}/modal/builder/README.md +0 -0
  159. {modal-1.5.3 → modal-1.5.3.dev0}/modal/builder/base-images.json +0 -0
  160. {modal-1.5.3 → modal-1.5.3.dev0}/modal/call_graph.py +0 -0
  161. {modal-1.5.3 → modal-1.5.3.dev0}/modal/cli/__init__.py +0 -0
  162. {modal-1.5.3 → modal-1.5.3.dev0}/modal/cli/_download.py +0 -0
  163. {modal-1.5.3 → modal-1.5.3.dev0}/modal/cli/_help.py +0 -0
  164. {modal-1.5.3 → modal-1.5.3.dev0}/modal/cli/_traceback.py +0 -0
  165. {modal-1.5.3 → modal-1.5.3.dev0}/modal/cli/app.py +0 -0
  166. {modal-1.5.3 → modal-1.5.3.dev0}/modal/cli/bootstrap.py +0 -0
  167. {modal-1.5.3 → modal-1.5.3.dev0}/modal/cli/changelog.py +0 -0
  168. {modal-1.5.3 → modal-1.5.3.dev0}/modal/cli/container.py +0 -0
  169. {modal-1.5.3 → modal-1.5.3.dev0}/modal/cli/curl.py +0 -0
  170. {modal-1.5.3 → modal-1.5.3.dev0}/modal/cli/dict.py +0 -0
  171. {modal-1.5.3 → modal-1.5.3.dev0}/modal/cli/entry_point.py +0 -0
  172. {modal-1.5.3 → modal-1.5.3.dev0}/modal/cli/image.py +0 -0
  173. {modal-1.5.3 → modal-1.5.3.dev0}/modal/cli/import_refs.py +0 -0
  174. {modal-1.5.3 → modal-1.5.3.dev0}/modal/cli/logo.py +0 -0
  175. {modal-1.5.3 → modal-1.5.3.dev0}/modal/cli/programs/__init__.py +0 -0
  176. {modal-1.5.3 → modal-1.5.3.dev0}/modal/cli/programs/run_jupyter.py +0 -0
  177. {modal-1.5.3 → modal-1.5.3.dev0}/modal/cli/programs/vscode.py +0 -0
  178. {modal-1.5.3 → modal-1.5.3.dev0}/modal/cli/queues.py +0 -0
  179. {modal-1.5.3 → modal-1.5.3.dev0}/modal/cli/run.py +0 -0
  180. {modal-1.5.3 → modal-1.5.3.dev0}/modal/cli/secret.py +0 -0
  181. {modal-1.5.3 → modal-1.5.3.dev0}/modal/cli/selector.py +0 -0
  182. {modal-1.5.3 → modal-1.5.3.dev0}/modal/cli/skills.py +0 -0
  183. {modal-1.5.3 → modal-1.5.3.dev0}/modal/cli/token.py +0 -0
  184. {modal-1.5.3 → modal-1.5.3.dev0}/modal/cli/utils.py +0 -0
  185. {modal-1.5.3 → modal-1.5.3.dev0}/modal/cli/volume.py +0 -0
  186. {modal-1.5.3 → modal-1.5.3.dev0}/modal/cli/workspace.py +0 -0
  187. {modal-1.5.3 → modal-1.5.3.dev0}/modal/dict.py +0 -0
  188. {modal-1.5.3 → modal-1.5.3.dev0}/modal/dict.pyi +0 -0
  189. {modal-1.5.3 → modal-1.5.3.dev0}/modal/experimental/flash.py +0 -0
  190. {modal-1.5.3 → modal-1.5.3.dev0}/modal/experimental/flash.pyi +0 -0
  191. {modal-1.5.3 → modal-1.5.3.dev0}/modal/experimental/ipython.py +0 -0
  192. {modal-1.5.3 → modal-1.5.3.dev0}/modal/file_io.py +0 -0
  193. {modal-1.5.3 → modal-1.5.3.dev0}/modal/file_io.pyi +0 -0
  194. {modal-1.5.3 → modal-1.5.3.dev0}/modal/functions.py +0 -0
  195. {modal-1.5.3 → modal-1.5.3.dev0}/modal/image.py +0 -0
  196. {modal-1.5.3 → modal-1.5.3.dev0}/modal/image.pyi +0 -0
  197. {modal-1.5.3 → modal-1.5.3.dev0}/modal/io_streams.py +0 -0
  198. {modal-1.5.3 → modal-1.5.3.dev0}/modal/io_streams.pyi +0 -0
  199. {modal-1.5.3 → modal-1.5.3.dev0}/modal/network_file_system.py +0 -0
  200. {modal-1.5.3 → modal-1.5.3.dev0}/modal/network_file_system.pyi +0 -0
  201. {modal-1.5.3 → modal-1.5.3.dev0}/modal/object.py +0 -0
  202. {modal-1.5.3 → modal-1.5.3.dev0}/modal/object.pyi +0 -0
  203. {modal-1.5.3 → modal-1.5.3.dev0}/modal/output.py +0 -0
  204. {modal-1.5.3 → modal-1.5.3.dev0}/modal/parallel_map.py +0 -0
  205. {modal-1.5.3 → modal-1.5.3.dev0}/modal/parallel_map.pyi +0 -0
  206. {modal-1.5.3 → modal-1.5.3.dev0}/modal/partial_function.py +0 -0
  207. {modal-1.5.3 → modal-1.5.3.dev0}/modal/proxy.py +0 -0
  208. {modal-1.5.3 → modal-1.5.3.dev0}/modal/proxy.pyi +0 -0
  209. {modal-1.5.3 → modal-1.5.3.dev0}/modal/py.typed +0 -0
  210. {modal-1.5.3 → modal-1.5.3.dev0}/modal/queue.py +0 -0
  211. {modal-1.5.3 → modal-1.5.3.dev0}/modal/queue.pyi +0 -0
  212. {modal-1.5.3 → modal-1.5.3.dev0}/modal/retries.py +0 -0
  213. {modal-1.5.3 → modal-1.5.3.dev0}/modal/running_app.py +0 -0
  214. {modal-1.5.3 → modal-1.5.3.dev0}/modal/scheduler_placement.py +0 -0
  215. {modal-1.5.3 → modal-1.5.3.dev0}/modal/server.py +0 -0
  216. {modal-1.5.3 → modal-1.5.3.dev0}/modal/serving.pyi +0 -0
  217. {modal-1.5.3 → modal-1.5.3.dev0}/modal/skills/modal/SKILL.md +0 -0
  218. {modal-1.5.3 → modal-1.5.3.dev0}/modal/stream_type.py +0 -0
  219. {modal-1.5.3 → modal-1.5.3.dev0}/modal/token_flow.py +0 -0
  220. {modal-1.5.3 → modal-1.5.3.dev0}/modal/token_flow.pyi +0 -0
  221. {modal-1.5.3 → modal-1.5.3.dev0}/modal/volume.py +0 -0
  222. {modal-1.5.3 → modal-1.5.3.dev0}/modal/volume.pyi +0 -0
  223. {modal-1.5.3 → modal-1.5.3.dev0}/modal/workspace.py +0 -0
  224. {modal-1.5.3 → modal-1.5.3.dev0}/modal.egg-info/dependency_links.txt +0 -0
  225. {modal-1.5.3 → modal-1.5.3.dev0}/modal.egg-info/entry_points.txt +0 -0
  226. {modal-1.5.3 → modal-1.5.3.dev0}/modal.egg-info/requires.txt +0 -0
  227. {modal-1.5.3 → modal-1.5.3.dev0}/modal.egg-info/top_level.txt +0 -0
  228. {modal-1.5.3 → modal-1.5.3.dev0}/modal_docs/__init__.py +0 -0
  229. {modal-1.5.3 → modal-1.5.3.dev0}/modal_docs/gen_cli_docs.py +0 -0
  230. {modal-1.5.3 → modal-1.5.3.dev0}/modal_docs/gen_cli_docs_main.py +0 -0
  231. {modal-1.5.3 → modal-1.5.3.dev0}/modal_docs/gen_reference_docs_main.py +0 -0
  232. {modal-1.5.3 → modal-1.5.3.dev0}/modal_docs/mdmd/__init__.py +0 -0
  233. {modal-1.5.3 → modal-1.5.3.dev0}/modal_docs/mdmd/signatures.py +0 -0
  234. {modal-1.5.3 → modal-1.5.3.dev0}/modal_proto/__init__.py +0 -0
  235. {modal-1.5.3 → modal-1.5.3.dev0}/modal_proto/py.typed +0 -0
  236. {modal-1.5.3 → modal-1.5.3.dev0}/modal_version/__main__.py +0 -0
  237. {modal-1.5.3 → modal-1.5.3.dev0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.5.3
3
+ Version: 1.5.3.dev0
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License-Expression: Apache-2.0
@@ -15,7 +15,6 @@ class ClusterInfo:
15
15
  cluster_id: str
16
16
  container_ips: list[str]
17
17
  container_ipv4_ips: list[str]
18
- fabric_ids: list[str]
19
18
 
20
19
 
21
20
  cluster_info: ClusterInfo | None = None
@@ -30,14 +29,6 @@ def get_cluster_info() -> ClusterInfo:
30
29
  return cluster_info
31
30
 
32
31
 
33
- def get_fabric_peers() -> list[int]:
34
- info = get_cluster_info()
35
- if info.rank >= len(info.fabric_ids) or not info.fabric_ids[info.rank]:
36
- return [info.rank]
37
- own_fabric_id = info.fabric_ids[info.rank]
38
- return [rank for rank, fabric_id in enumerate(info.fabric_ids) if fabric_id == own_fabric_id]
39
-
40
-
41
32
  async def _initialize_clustered_function(client: _Client, task_id: str, world_size: int):
42
33
  global cluster_info
43
34
 
@@ -79,7 +70,6 @@ async def _initialize_clustered_function(client: _Client, task_id: str, world_si
79
70
  cluster_id=resp.cluster_id,
80
71
  container_ips=resp.container_ips,
81
72
  container_ipv4_ips=resp.container_ipv4_ips,
82
- fabric_ids=resp.fabric_ids,
83
73
  )
84
74
  else:
85
75
  cluster_info = ClusterInfo(
@@ -87,7 +77,6 @@ async def _initialize_clustered_function(client: _Client, task_id: str, world_si
87
77
  cluster_id="", # No cluster ID for single-node # TODO(irfansharif): Is this right?
88
78
  container_ips=[container_ip],
89
79
  container_ipv4_ips=[], # No IPv4 IPs for single-node
90
- fabric_ids=[],
91
80
  )
92
81
 
93
82
 
@@ -3,17 +3,14 @@ import types
3
3
  import typing_extensions
4
4
 
5
5
  class ClusterInfo:
6
- """ClusterInfo(rank: int, cluster_id: str, container_ips: list[str], container_ipv4_ips: list[str], fabric_ids: list[str])"""
6
+ """ClusterInfo(rank: int, cluster_id: str, container_ips: list[str], container_ipv4_ips: list[str])"""
7
7
 
8
8
  rank: int
9
9
  cluster_id: str
10
10
  container_ips: list[str]
11
11
  container_ipv4_ips: list[str]
12
- fabric_ids: list[str]
13
12
 
14
- def __init__(
15
- self, rank: int, cluster_id: str, container_ips: list[str], container_ipv4_ips: list[str], fabric_ids: list[str]
16
- ) -> None:
13
+ def __init__(self, rank: int, cluster_id: str, container_ips: list[str], container_ipv4_ips: list[str]) -> None:
17
14
  """Initialize self. See help(type(self)) for accurate signature."""
18
15
  ...
19
16
 
@@ -26,7 +23,6 @@ class ClusterInfo:
26
23
  ...
27
24
 
28
25
  def get_cluster_info() -> ClusterInfo: ...
29
- def get_fabric_peers() -> list[int]: ...
30
26
  async def _initialize_clustered_function(client: modal.client._Client, task_id: str, world_size: int): ...
31
27
 
32
28
  class __initialize_clustered_function_spec(typing_extensions.Protocol):
@@ -145,7 +145,7 @@ def call_function(
145
145
  item_count += 1
146
146
 
147
147
  await container_io_manager._send_outputs.aio(
148
- io_context.output_items_generator_done(started_at, item_count)
148
+ started_at, io_context.output_items_generator_done(started_at, item_count)
149
149
  )
150
150
  else:
151
151
  value = await io_context.call_function_async()
@@ -182,7 +182,9 @@ def call_function(
182
182
  container_io_manager._queue_put(generator_queue, value)
183
183
  item_count += 1
184
184
 
185
- container_io_manager._send_outputs(io_context.output_items_generator_done(started_at, item_count))
185
+ container_io_manager._send_outputs(
186
+ started_at, io_context.output_items_generator_done(started_at, item_count)
187
+ )
186
188
  else:
187
189
  values = io_context.call_function_sync()
188
190
  container_io_manager.push_outputs(io_context, started_at, values)
@@ -16,13 +16,11 @@ from modal_proto import api_pb2
16
16
  from ._load_context import LoadContext
17
17
  from ._object import _Object
18
18
  from ._resolver import Resolver
19
- from ._utils.deprecation import deprecation_warning
20
19
  from ._utils.name_utils import check_environment_name
21
- from ._utils.time_utils import is_utc_month_aligned, parse_billing_cycle
22
20
  from .client import _Client
23
21
  from .config import config, logger
24
22
  from .exception import InvalidError, WorkspaceManagementError
25
- from .types import BillingReportItem, EnvironmentBillingSummary
23
+ from .types import BillingReportItem
26
24
 
27
25
 
28
26
  @dataclass(frozen=True)
@@ -105,38 +103,63 @@ class _EnvironmentManager:
105
103
  await client.stub.EnvironmentDelete(api_pb2.EnvironmentDeleteRequest(name=name))
106
104
 
107
105
 
108
- class _EnvironmentRolesManager:
109
- """mdmd:namespace"""
106
+ def _role_to_proto(role: str) -> "api_pb2.EnvironmentRole.ValueType":
107
+ match role:
108
+ case "viewer":
109
+ return api_pb2.ENVIRONMENT_ROLE_VIEWER
110
+ case "contributor":
111
+ return api_pb2.ENVIRONMENT_ROLE_CONTRIBUTOR
112
+ case _:
113
+ raise InvalidError(f"Invalid Environment role: {role!r} (expected 'viewer' or 'contributor')")
114
+
115
+
116
+ def _role_from_proto(proto_value: int) -> str:
117
+ match proto_value:
118
+ case api_pb2.ENVIRONMENT_ROLE_VIEWER:
119
+ return "viewer"
120
+ case api_pb2.ENVIRONMENT_ROLE_CONTRIBUTOR:
121
+ return "contributor"
122
+ case _:
123
+ raise ValueError(f"Unknown environment role: {proto_value}")
124
+
125
+
126
+ class _EnvironmentMembersManager:
127
+ """mdmd:namespace
128
+ Namespace with methods for managing the membership of a restricted Environment.
129
+
130
+ See https://modal.com/docs/guide/rbac for more information on restricted Environments.
131
+ """
110
132
 
111
133
  def __init__(self, environment: "_Environment"):
112
134
  """mdmd:hidden"""
113
135
  self._environment = environment
114
136
 
115
137
  async def list(self) -> dict[Literal["users", "service_users"], dict[str, str]]:
116
- """Enumerate the Environment Role for each user and service user in the workspace.
138
+ """Return the members of a restricted Environment with their roles.
117
139
 
118
140
  **Examples:**
119
141
 
120
142
  ```python notest
121
- roles = modal.Environment.from_name("my-env").roles.list()
122
- print(roles)
143
+ members = modal.Environment.from_name("my-restricted-env").members.list()
144
+ print(members)
123
145
  # {
124
- # "users": {"alice": "contributor", "bob": "viewer", "carol": "contributor"},
125
- # "service_users": {"alice-bot": "contributor", "ops-bot": "viewer", "ci-bot": "no-access"},
146
+ # "users": {"alice": "contributor", "bob": "viewer"},
147
+ # "service_users": {"alice-bot": "contributor"},
126
148
  # }
127
149
  ```
128
150
  """
129
151
  await self._environment.hydrate()
130
- req = api_pb2.EnvironmentGetRolesRequest(environment_id=self._environment.object_id)
131
- resp = await self._environment.client.stub.EnvironmentGetRoles(req)
152
+ req = api_pb2.EnvironmentGetManagedRequest(environment_id=self._environment.object_id)
153
+ resp = await self._environment.client.stub.EnvironmentGetManaged(req)
132
154
 
133
155
  users: dict[str, str] = {}
134
156
  service_users: dict[str, str] = {}
135
157
  for principal in resp.principal_roles:
158
+ role = _role_from_proto(principal.role)
136
159
  if principal.user_id:
137
- users[principal.user_name] = principal.role_str
160
+ users[principal.user_name] = role
138
161
  elif principal.service_user_id:
139
- service_users[principal.service_user_name] = principal.role_str
162
+ service_users[principal.service_user_name] = role
140
163
 
141
164
  return {"users": users, "service_users": service_users}
142
165
 
@@ -146,17 +169,16 @@ class _EnvironmentRolesManager:
146
169
  users: Mapping[str, str] | None = None,
147
170
  service_users: Mapping[str, str] | None = None,
148
171
  ) -> None:
149
- """Update the Environment Role of users and service users.
172
+ """Add or modify roles for members of a restricted Environment.
150
173
 
151
- Each role is one of 'contributor', 'viewer', or 'no-access'. Service users can be
152
- assigned a role on any Environment, while workspace members can only be assigned a
153
- role on restricted Environments.
174
+ Each user or service user will be added to the Environment if not currently a member;
175
+ if already a member, the user or service user's role will be updated.
154
176
 
155
177
  **Examples:**
156
178
 
157
179
  ```python notest
158
180
  env = modal.Environment.from_name("my-restricted-env")
159
- env.roles.update(
181
+ env.members.update(
160
182
  users={"alice": "contributor", "bob": "viewer"},
161
183
  service_users={"alice-bot": "contributor"},
162
184
  )
@@ -166,13 +188,13 @@ class _EnvironmentRolesManager:
166
188
  users = users or {}
167
189
  service_users = service_users or {}
168
190
 
169
- req = api_pb2.EnvironmentGetRolesRequest(environment_id=self._environment.object_id)
170
- resp = await self._environment.client.stub.EnvironmentGetRoles(req)
191
+ req = api_pb2.EnvironmentGetManagedRequest(environment_id=self._environment.object_id)
192
+ resp = await self._environment.client.stub.EnvironmentGetManaged(req)
171
193
 
172
- # EnvironmentGetRoles returns every workspace principal
194
+ # Both current members and additional eligible workspace principals can be assigned a role
173
195
  user_name_to_id: dict[str, str] = {}
174
196
  service_user_name_to_id: dict[str, str] = {}
175
- for principal in resp.principal_roles:
197
+ for principal in [*resp.principal_roles, *resp.additional_roles]:
176
198
  if principal.user_id:
177
199
  user_name_to_id[principal.user_name] = principal.user_id
178
200
  elif principal.service_user_id:
@@ -185,7 +207,7 @@ class _EnvironmentRolesManager:
185
207
  requests[f"User {name!r}"] = api_pb2.EnvironmentRoleSetRequest(
186
208
  environment_id=self._environment.object_id,
187
209
  user_id=user_name_to_id[name],
188
- role_str=role,
210
+ role=_role_to_proto(role),
189
211
  )
190
212
  for name, role in service_users.items():
191
213
  if name not in service_user_name_to_id:
@@ -193,70 +215,35 @@ class _EnvironmentRolesManager:
193
215
  requests[f"Service user {name!r}"] = api_pb2.EnvironmentRoleSetRequest(
194
216
  environment_id=self._environment.object_id,
195
217
  service_user_id=service_user_name_to_id[name],
196
- role_str=role,
218
+ role=_role_to_proto(role),
197
219
  )
198
220
 
199
221
  await self._dispatch_role_updates(requests)
200
222
 
201
- async def _dispatch_role_updates(self, requests: dict[str, api_pb2.EnvironmentRoleSetRequest]) -> None:
202
- """Send batched EnvironmentRoleSet RPCs and report all errors encountered."""
203
- results = await asyncio.gather(
204
- *(self._environment.client.stub.EnvironmentRoleSet(req) for req in requests.values()),
205
- return_exceptions=True,
206
- )
207
- errors = [(label, result) for label, result in zip(requests.keys(), results) if isinstance(result, Exception)]
208
- if errors:
209
- n = len(errors)
210
- header = f"{n} error{'s' if n != 1 else ''} occurred while updating Environment roles:"
211
- details = "\n".join(f" - {label}: {e}" for label, e in errors)
212
- raise WorkspaceManagementError(f"{header}\n{details}")
213
-
214
-
215
- # Deprecated alias for `_EnvironmentRolesManager`; each method warns and delegates.
216
- class _EnvironmentMembersManager:
217
- """mdmd:hidden"""
218
-
219
- def __init__(self, environment: "_Environment"):
220
- """mdmd:hidden"""
221
- self._environment = environment
222
-
223
- async def list(self) -> dict[Literal["users", "service_users"], dict[str, str]]:
224
- deprecation_warning(
225
- (2026, 7, 23),
226
- "`Environment.members.list()` is deprecated; use `Environment.roles.list()` instead.",
227
- )
228
- return await _EnvironmentRolesManager(self._environment).list()
229
-
230
- async def update(
231
- self,
232
- *,
233
- users: Mapping[str, str] | None = None,
234
- service_users: Mapping[str, str] | None = None,
235
- ) -> None:
236
- deprecation_warning(
237
- (2026, 7, 23),
238
- "`Environment.members.update()` is deprecated; use `Environment.roles.update()` instead.",
239
- )
240
- await _EnvironmentRolesManager(self._environment).update(users=users, service_users=service_users)
241
-
242
223
  async def remove(
243
224
  self,
244
225
  *,
245
226
  users: Iterable[str] | None = None,
246
227
  service_users: Iterable[str] | None = None,
247
228
  ) -> None:
248
- """Remove the Environment Role of users and service users, reverting them to the default."""
249
- deprecation_warning(
250
- (2026, 7, 23),
251
- "`Environment.members.remove()` is deprecated. Environment Roles are now explicit; "
252
- "set a role (e.g. 'no-access') with `Environment.roles.update()` instead.",
229
+ """Remove members from a restricted Environment.
230
+
231
+ **Examples:**
232
+
233
+ ```python notest
234
+ env = modal.Environment.from_name("my-restricted-env")
235
+ env.members.remove(
236
+ users=["alice"],
237
+ service_users=["alice-bot"],
253
238
  )
239
+ ```
240
+ """
254
241
  await self._environment.hydrate()
255
242
  users = users or []
256
243
  service_users = service_users or []
257
244
 
258
- req = api_pb2.EnvironmentGetRolesRequest(environment_id=self._environment.object_id)
259
- resp = await self._environment.client.stub.EnvironmentGetRoles(req)
245
+ req = api_pb2.EnvironmentGetManagedRequest(environment_id=self._environment.object_id)
246
+ resp = await self._environment.client.stub.EnvironmentGetManaged(req)
260
247
 
261
248
  user_name_to_id: dict[str, str] = {}
262
249
  service_user_name_to_id: dict[str, str] = {}
@@ -269,7 +256,7 @@ class _EnvironmentMembersManager:
269
256
  requests: dict[str, api_pb2.EnvironmentRoleSetRequest] = {}
270
257
  for name in users:
271
258
  if name not in user_name_to_id:
272
- raise InvalidError(f"User {name!r} not found in workspace")
259
+ raise InvalidError(f"User {name!r} is not a member of this Environment")
273
260
  requests[f"User {name!r}"] = api_pb2.EnvironmentRoleSetRequest(
274
261
  environment_id=self._environment.object_id,
275
262
  user_id=user_name_to_id[name],
@@ -277,14 +264,27 @@ class _EnvironmentMembersManager:
277
264
  )
278
265
  for name in service_users:
279
266
  if name not in service_user_name_to_id:
280
- raise InvalidError(f"Service user {name!r} not found in workspace")
267
+ raise InvalidError(f"Service user {name!r} is not a member of this Environment")
281
268
  requests[f"Service user {name!r}"] = api_pb2.EnvironmentRoleSetRequest(
282
269
  environment_id=self._environment.object_id,
283
270
  service_user_id=service_user_name_to_id[name],
284
271
  role=api_pb2.ENVIRONMENT_ROLE_UNSPECIFIED,
285
272
  )
286
273
 
287
- await _EnvironmentRolesManager(self._environment)._dispatch_role_updates(requests)
274
+ await self._dispatch_role_updates(requests)
275
+
276
+ async def _dispatch_role_updates(self, requests: dict[str, api_pb2.EnvironmentRoleSetRequest]) -> None:
277
+ """Send batched EnvironmentRoleSet RPCs and report all errors encountered."""
278
+ results = await asyncio.gather(
279
+ *(self._environment.client.stub.EnvironmentRoleSet(req) for req in requests.values()),
280
+ return_exceptions=True,
281
+ )
282
+ errors = [(label, result) for label, result in zip(requests.keys(), results) if isinstance(result, Exception)]
283
+ if errors:
284
+ n = len(errors)
285
+ header = f"{n} error{'s' if n != 1 else ''} occurred while updating Environment members:"
286
+ details = "\n".join(f" - {label}: {e}" for label, e in errors)
287
+ raise WorkspaceManagementError(f"{header}\n{details}")
288
288
 
289
289
 
290
290
  class _Environment(_Object, type_prefix="en"):
@@ -307,18 +307,8 @@ class _Environment(_Object, type_prefix="en"):
307
307
  def objects(cls) -> _EnvironmentManager:
308
308
  return _EnvironmentManager()
309
309
 
310
- @property
311
- def roles(self) -> "_EnvironmentRolesManager":
312
- """Namespace with methods for managing the Environment Roles of users and service users.
313
-
314
- See https://modal.com/docs/guide/rbac for more information on Environment Roles.
315
- """
316
- return _EnvironmentRolesManager(self)
317
-
318
310
  @property
319
311
  def members(self) -> "_EnvironmentMembersManager":
320
- """mdmd:hidden"""
321
- # Deprecated alias for `Environment.roles`.
322
312
  return _EnvironmentMembersManager(self)
323
313
 
324
314
  # TODO(michael) Keeping this private for now until we decide what else should be in it
@@ -403,12 +393,13 @@ class _Environment(_Object, type_prefix="en"):
403
393
 
404
394
  @property
405
395
  def billing(self) -> "_EnvironmentBillingManager":
406
- """Namespace for Environment billing APIs."""
407
396
  return _EnvironmentBillingManager(self)
408
397
 
409
398
 
410
399
  class _EnvironmentBillingManager:
411
- """mdmd:namespace"""
400
+ """mdmd:namespace
401
+ Namespace for Environment billing APIs
402
+ """
412
403
 
413
404
  def __init__(self, environment: _Environment):
414
405
  """mdmd:ignore"""
@@ -445,7 +436,7 @@ class _EnvironmentBillingManager:
445
436
  - [`modal environment billing report`](https://modal.com/docs/cli/latest/environment#modal-environment-billing-report):
446
437
  An environment report CLI that has convenience features around relative time range queries
447
438
  and JSON/CSV output.
448
- - [`Workspace.billing.report()`](https://modal.com/docs/sdk/py/latest/Workspace#billingreport):
439
+ - [`Workspace.billing.report()`](https://modal.com/docs/sdk/py/latest/modal.Workspace#billingreport):
449
440
  An analogous report API for the entire Workspace.
450
441
 
451
442
  """
@@ -481,71 +472,6 @@ class _EnvironmentBillingManager:
481
472
  async for pb_item in self._environment.client.stub.WorkspaceBillingReport.unary_stream(request)
482
473
  ]
483
474
 
484
- async def summary(
485
- self,
486
- cycle: str | datetime | None = None, # Start of the summary, inclusive
487
- ) -> EnvironmentBillingSummary:
488
- """Return a summary of environment cost over a single billing cycle determined by `cycle`.
489
-
490
- Unlike the analogous `Workspace.billing.summary()`, this API only emits metered cost
491
- information. This is because billing adjustments due to credits, free storage, etc. are
492
- applied at the Workspace level, and thus cannot be attributed to individual Environments.
493
-
494
- Args:
495
- cycle: Start of the summary, inclusive. Must be the first of a month, and must be in UTC
496
- or timezone-naive (interpreted as UTC). If provided as a string, it must either be
497
- formatted as an ISO 8601 month (YYYY-MM), or must be one of the convenience spellings
498
- "this month" or "last month". If not provided, `cycle` defaults to the first of the
499
- current month (in which case a summary is generated for the current billing cycle).
500
-
501
- Returns:
502
- A single `EnvironmentBillingSummary` dataclass containing the following fields:
503
- - `metered_cost` representing cost before any adjustments, and
504
- - `metered_cost_breakdown` containing a breakdown of that cost by the Modal resources
505
- that generated it. The exact keys of this are subject to change as Modal's billing
506
- model evolves.
507
-
508
- All values are reported as `decimal.Decimal`s.
509
-
510
- See also:
511
- - [`modal environment billing summary`](https://modal.com/docs/cli/latest/billing#modal-environment-billing-summary):
512
- An environment summary CLI that has convenience features around relative time range queries.
513
- - [`Environment.billing.report()`](https://modal.com/docs/sdk/py/latest/Environment#billingreport):
514
- An analogous report API that is scoped to a specific Environment.
515
- """
516
-
517
- if cycle is None:
518
- cycle = datetime.now(timezone.utc).replace(
519
- day=1,
520
- hour=0,
521
- minute=0,
522
- second=0,
523
- microsecond=0,
524
- )
525
- elif isinstance(cycle, str):
526
- cycle = parse_billing_cycle(cycle)
527
-
528
- if cycle.tzinfo is None:
529
- cycle = cycle.replace(tzinfo=timezone.utc)
530
- elif cycle.tzinfo != timezone.utc:
531
- raise InvalidError("Timezone-aware 'cycle' parameter must be in UTC.")
532
-
533
- if not is_utc_month_aligned(cycle):
534
- raise InvalidError("Provided 'cycle' parameter must be the first of a month.")
535
-
536
- if cycle > datetime.now(timezone.utc):
537
- raise InvalidError("Provided 'cycle' parameter cannot be in the future.")
538
-
539
- if not self._environment.is_hydrated:
540
- await self._environment.hydrate()
541
-
542
- request = api_pb2.EnvironmentBillingSummaryRequest(environment_id=self._environment.object_id)
543
- request.start_timestamp.FromDatetime(cycle)
544
-
545
- return EnvironmentBillingSummary._from_proto(
546
- await self._environment.client.stub.EnvironmentBillingSummary(request)
547
- )
548
-
549
475
 
550
476
  ENVIRONMENT_CACHE: dict[str, _Environment] = {}
551
477
 
@@ -621,4 +547,4 @@ def ensure_env(environment_name: str | None = None) -> str:
621
547
  if environment_name is not None:
622
548
  config.override_locally("environment", environment_name)
623
549
 
624
- return config.get("environment") or ""
550
+ return config.get("environment")
@@ -171,7 +171,7 @@ class _FunctionOptions:
171
171
  replace_secret_ids=bool(self.secrets),
172
172
  replace_volume_mounts=len(volume_mounts) > 0,
173
173
  volume_mounts=volume_mounts,
174
- cloud_bucket_mounts=cloud_bucket_mounts_to_proto(self.cloud_bucket_mounts)[0],
174
+ cloud_bucket_mounts=cloud_bucket_mounts_to_proto(self.cloud_bucket_mounts),
175
175
  replace_cloud_bucket_mounts=bool(self.cloud_bucket_mounts),
176
176
  resources=self.resources,
177
177
  retry_policy=self.retry_policy,