modal 1.4.4.dev9__tar.gz → 1.4.4.dev11__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 (219) hide show
  1. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/PKG-INFO +2 -2
  2. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/__init__.py +2 -0
  3. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_billing.py +4 -4
  4. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_clustered_functions.py +1 -2
  5. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_clustered_functions.pyi +2 -2
  6. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_container_entrypoint.py +13 -7
  7. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_environments.py +23 -23
  8. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_function_variants.py +34 -34
  9. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_functions.py +99 -101
  10. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_grpc_client.py +13 -12
  11. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_load_context.py +14 -14
  12. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_logs.py +7 -7
  13. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_object.py +31 -31
  14. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_output/manager.py +18 -18
  15. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_output/pty.py +8 -8
  16. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_output/rich.py +2 -1
  17. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_output/status.py +1 -3
  18. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_partial_function.py +46 -49
  19. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_resolver.py +3 -4
  20. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_resources.py +6 -6
  21. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_runtime/asgi.py +3 -3
  22. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_runtime/container_io_manager.py +60 -190
  23. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_runtime/container_io_manager.pyi +27 -80
  24. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_runtime/execution_context.py +4 -4
  25. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_runtime/gpu_memory_snapshot.py +4 -5
  26. modal-1.4.4.dev11/modal/_runtime/task_lifecycle_manager.py +199 -0
  27. modal-1.4.4.dev11/modal/_runtime/task_lifecycle_manager.pyi +102 -0
  28. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_runtime/user_code_imports.py +124 -66
  29. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_serialization.py +1 -1
  30. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_server.py +11 -12
  31. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_traceback.py +6 -5
  32. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_tunnel.py +1 -2
  33. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_utils/async_utils.py +19 -24
  34. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_utils/auth_token_manager.py +1 -2
  35. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_utils/blob_utils.py +22 -25
  36. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_utils/bytes_io_segment_payload.py +4 -3
  37. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_utils/deprecation.py +2 -1
  38. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_utils/docker_utils.py +2 -2
  39. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_utils/function_utils.py +20 -20
  40. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_utils/git_utils.py +2 -3
  41. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_utils/grpc_testing.py +2 -2
  42. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_utils/grpc_utils.py +16 -16
  43. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_utils/hash_utils.py +7 -6
  44. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_utils/http_utils.py +2 -2
  45. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_utils/jwt_utils.py +4 -4
  46. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_utils/mount_utils.py +8 -10
  47. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_utils/pattern_utils.py +2 -2
  48. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_utils/rand_pb_testing.py +4 -3
  49. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_utils/sandbox_fs_utils.py +10 -10
  50. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_utils/shell_utils.py +3 -4
  51. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_utils/task_command_router_client.py +167 -52
  52. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_utils/time_utils.py +4 -5
  53. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_vendor/a2wsgi_wsgi.py +6 -6
  54. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_vendor/cloudpickle.py +1 -1
  55. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_watcher.py +2 -3
  56. modal-1.4.4.dev11/modal/_workspace.py +116 -0
  57. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/app.py +106 -110
  58. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/app.pyi +1 -1
  59. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/call_graph.py +1 -2
  60. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/cli/_download.py +5 -6
  61. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/cli/_help.py +12 -12
  62. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/cli/_traceback.py +1 -2
  63. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/cli/app.py +17 -17
  64. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/cli/billing.py +5 -6
  65. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/cli/bootstrap.py +1 -2
  66. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/cli/changelog.py +6 -7
  67. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/cli/cluster.py +3 -4
  68. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/cli/container.py +10 -11
  69. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/cli/dashboard.py +1 -2
  70. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/cli/dict.py +6 -7
  71. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/cli/entry_point.py +1 -2
  72. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/cli/environment.py +3 -4
  73. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/cli/import_refs.py +4 -4
  74. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/cli/launch.py +9 -9
  75. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/cli/network_file_system.py +7 -8
  76. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/cli/profile.py +2 -3
  77. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/cli/queues.py +7 -8
  78. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/cli/run.py +11 -10
  79. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/cli/secret.py +5 -6
  80. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/cli/shell.py +21 -20
  81. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/cli/token.py +4 -5
  82. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/cli/utils.py +16 -17
  83. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/cli/volume.py +11 -12
  84. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/client.py +16 -16
  85. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/client.pyi +2 -2
  86. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/cloud_bucket_mount.py +5 -5
  87. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/cloud_bucket_mount.pyi +2 -1
  88. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/cls.py +40 -40
  89. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/cls.pyi +2 -2
  90. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/config.py +5 -4
  91. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/container_process.py +8 -8
  92. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/dict.py +25 -25
  93. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/exception.py +2 -2
  94. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/experimental/__init__.py +47 -7
  95. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/experimental/flash.py +23 -22
  96. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/file_io.py +15 -14
  97. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/file_io.pyi +8 -7
  98. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/file_pattern_matcher.py +6 -6
  99. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/functions.pyi +4 -2
  100. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/image.py +133 -137
  101. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/image.pyi +8 -14
  102. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/io_streams.py +146 -71
  103. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/io_streams.pyi +179 -24
  104. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/mount.py +29 -30
  105. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/mount.pyi +8 -4
  106. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/network_file_system.py +17 -17
  107. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/object.pyi +33 -75
  108. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/parallel_map.py +16 -17
  109. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/proxy.py +3 -4
  110. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/queue.py +37 -37
  111. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/retries.py +1 -2
  112. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/runner.py +11 -11
  113. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/running_app.py +5 -6
  114. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/sandbox.py +250 -181
  115. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/sandbox.pyi +66 -11
  116. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/sandbox_fs.py +4 -4
  117. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/scheduler_placement.py +5 -6
  118. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/secret.py +23 -30
  119. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/serving.py +5 -5
  120. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/snapshot.py +3 -5
  121. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/token_flow.py +8 -9
  122. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/volume.py +65 -73
  123. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/volume.pyi +3 -3
  124. modal-1.4.4.dev11/modal/workspace.py +12 -0
  125. modal-1.4.4.dev11/modal/workspace.pyi +105 -0
  126. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal.egg-info/PKG-INFO +2 -2
  127. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal.egg-info/SOURCES.txt +5 -0
  128. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal.egg-info/requires.txt +1 -1
  129. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal_docs/gen_cli_docs.py +2 -2
  130. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal_docs/mdmd/mdmd.py +3 -3
  131. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal_proto/api_pb2.py +802 -802
  132. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal_proto/api_pb2.pyi +4 -1
  133. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal_version/__init__.py +1 -1
  134. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/pyproject.toml +18 -5
  135. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/LICENSE +0 -0
  136. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/README.md +0 -0
  137. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/__main__.py +0 -0
  138. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_ipython.py +0 -0
  139. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_location.py +0 -0
  140. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_output/__init__.py +0 -0
  141. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_runtime/__init__.py +0 -0
  142. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_runtime/execution_context.pyi +0 -0
  143. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_runtime/telemetry.py +0 -0
  144. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_runtime/user_code_event_loop.py +0 -0
  145. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_tunnel.pyi +0 -0
  146. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_type_manager.py +0 -0
  147. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_utils/__init__.py +0 -0
  148. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_utils/app_utils.py +0 -0
  149. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_utils/browser_utils.py +0 -0
  150. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_utils/logger.py +0 -0
  151. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_utils/name_utils.py +0 -0
  152. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_utils/package_utils.py +0 -0
  153. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_vendor/__init__.py +0 -0
  154. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_vendor/tblib.py +0 -0
  155. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/_vendor/version.py +0 -0
  156. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/billing.py +0 -0
  157. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/builder/2023.12.312.txt +0 -0
  158. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/builder/2023.12.txt +0 -0
  159. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/builder/2024.04.txt +0 -0
  160. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/builder/2024.10.txt +0 -0
  161. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/builder/2025.06.txt +0 -0
  162. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/builder/PREVIEW.txt +0 -0
  163. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/builder/README.md +0 -0
  164. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/builder/base-images.json +0 -0
  165. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/cli/__init__.py +0 -0
  166. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/cli/config.py +0 -0
  167. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/cli/logo.py +0 -0
  168. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/cli/programs/__init__.py +0 -0
  169. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/cli/programs/run_jupyter.py +0 -0
  170. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/cli/programs/vscode.py +0 -0
  171. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/cli/selector.py +0 -0
  172. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/container_process.pyi +0 -0
  173. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/dict.pyi +0 -0
  174. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/environments.py +0 -0
  175. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/environments.pyi +0 -0
  176. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/experimental/flash.pyi +0 -0
  177. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/experimental/ipython.py +0 -0
  178. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/functions.py +0 -0
  179. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/network_file_system.pyi +0 -0
  180. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/object.py +0 -0
  181. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/output.py +0 -0
  182. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/parallel_map.pyi +0 -0
  183. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/partial_function.py +0 -0
  184. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/partial_function.pyi +1 -1
  185. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/proxy.pyi +0 -0
  186. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/py.typed +0 -0
  187. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/queue.pyi +0 -0
  188. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/runner.pyi +0 -0
  189. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/sandbox_fs.pyi +0 -0
  190. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/schedule.py +0 -0
  191. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/secret.pyi +0 -0
  192. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/server.py +0 -0
  193. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/server.pyi +0 -0
  194. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/serving.pyi +0 -0
  195. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/snapshot.pyi +0 -0
  196. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/stream_type.py +0 -0
  197. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal/token_flow.pyi +0 -0
  198. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal.egg-info/dependency_links.txt +0 -0
  199. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal.egg-info/entry_points.txt +0 -0
  200. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal.egg-info/top_level.txt +0 -0
  201. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal_docs/__init__.py +0 -0
  202. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal_docs/gen_cli_docs_main.py +0 -0
  203. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal_docs/gen_reference_docs.py +0 -0
  204. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal_docs/gen_reference_docs_main.py +0 -0
  205. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal_docs/mdmd/__init__.py +0 -0
  206. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal_docs/mdmd/signatures.py +0 -0
  207. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal_proto/__init__.py +0 -0
  208. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal_proto/api_grpc.py +0 -0
  209. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal_proto/api_pb2_grpc.py +0 -0
  210. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal_proto/api_pb2_grpc.pyi +0 -0
  211. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal_proto/modal_api_grpc.py +0 -0
  212. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal_proto/py.typed +0 -0
  213. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal_proto/task_command_router_grpc.py +0 -0
  214. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal_proto/task_command_router_pb2.py +0 -0
  215. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal_proto/task_command_router_pb2.pyi +0 -0
  216. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal_proto/task_command_router_pb2_grpc.py +0 -0
  217. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal_proto/task_command_router_pb2_grpc.pyi +0 -0
  218. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/modal_version/__main__.py +0 -0
  219. {modal-1.4.4.dev9 → modal-1.4.4.dev11}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.4.4.dev9
3
+ Version: 1.4.4.dev11
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License-Expression: Apache-2.0
@@ -23,7 +23,7 @@ Requires-Dist: grpclib<0.4.10,>=0.4.7; python_version < "3.14"
23
23
  Requires-Dist: grpclib<0.4.10,>=0.4.9; python_version >= "3.14"
24
24
  Requires-Dist: protobuf!=4.24.0,<7.0,>=3.19
25
25
  Requires-Dist: rich>=12.0.0
26
- Requires-Dist: synchronicity~=0.12.1
26
+ Requires-Dist: synchronicity~=0.12.3
27
27
  Requires-Dist: toml
28
28
  Requires-Dist: types-certifi
29
29
  Requires-Dist: types-toml
@@ -45,6 +45,7 @@ try:
45
45
  from .secret import Secret
46
46
  from .snapshot import SandboxSnapshot
47
47
  from .volume import Volume
48
+ from .workspace import Workspace
48
49
  except Exception:
49
50
  print()
50
51
  print("#" * 80)
@@ -81,6 +82,7 @@ __all__ = [
81
82
  "Secret",
82
83
  "Tunnel",
83
84
  "Volume",
85
+ "Workspace",
84
86
  "asgi_app",
85
87
  "batched",
86
88
  "billing",
@@ -1,7 +1,7 @@
1
1
  # Copyright Modal Labs 2025
2
2
  from datetime import datetime, timezone
3
3
  from decimal import Decimal
4
- from typing import Optional, TypedDict
4
+ from typing import TypedDict
5
5
 
6
6
  from modal_proto import api_pb2
7
7
 
@@ -21,10 +21,10 @@ class WorkspaceBillingReportItem(TypedDict):
21
21
  async def _workspace_billing_report(
22
22
  *,
23
23
  start: datetime, # Start of the report, inclusive
24
- end: Optional[datetime] = None, # End of the report, exclusive
24
+ end: datetime | None = None, # End of the report, exclusive
25
25
  resolution: str = "d", # Resolution, e.g. "d" for daily or "h" for hourly
26
- tag_names: Optional[list[str]] = None, # Optional additional metadata to include
27
- client: Optional[_Client] = None,
26
+ tag_names: list[str] | None = None, # Optional additional metadata to include
27
+ client: _Client | None = None,
28
28
  ) -> list[WorkspaceBillingReportItem]:
29
29
  """Generate a tabular report of workspace usage by object and time.
30
30
 
@@ -2,7 +2,6 @@
2
2
  import os
3
3
  import socket
4
4
  from dataclasses import dataclass
5
- from typing import Optional
6
5
 
7
6
  from modal._utils.async_utils import synchronize_api
8
7
  from modal.client import _Client
@@ -18,7 +17,7 @@ class ClusterInfo:
18
17
  container_ipv4_ips: list[str]
19
18
 
20
19
 
21
- cluster_info: Optional[ClusterInfo] = None
20
+ cluster_info: ClusterInfo | None = None
22
21
 
23
22
 
24
23
  def get_cluster_info() -> ClusterInfo:
@@ -1,5 +1,5 @@
1
1
  import modal.client
2
- import typing
2
+ import types
3
3
  import typing_extensions
4
4
 
5
5
  class ClusterInfo:
@@ -31,4 +31,4 @@ class __initialize_clustered_function_spec(typing_extensions.Protocol):
31
31
 
32
32
  initialize_clustered_function: __initialize_clustered_function_spec
33
33
 
34
- cluster_info: typing.Optional[ClusterInfo]
34
+ cluster_info: ClusterInfo | None
@@ -21,7 +21,7 @@ import signal
21
21
  import threading
22
22
  import time
23
23
  import types
24
- from typing import TYPE_CHECKING, Any, Optional, cast
24
+ from typing import TYPE_CHECKING, Any, cast
25
25
 
26
26
  from google.protobuf.message import Message
27
27
 
@@ -40,8 +40,8 @@ from ._runtime import execution_context
40
40
  from ._runtime.container_io_manager import (
41
41
  ContainerIOManager,
42
42
  IOContext,
43
- UserException,
44
43
  )
44
+ from ._runtime.task_lifecycle_manager import UserException
45
45
 
46
46
  if TYPE_CHECKING:
47
47
  import modal._runtime.container_io_manager
@@ -268,7 +268,7 @@ def call_function(
268
268
 
269
269
  def get_serialized_user_class_and_function(
270
270
  function_def: api_pb2.Function, client: _Client
271
- ) -> tuple[Optional[type], Optional[types.FunctionType]]:
271
+ ) -> tuple[type | None, types.FunctionType | None]:
272
272
  if function_def.definition_type == api_pb2.Function.DEFINITION_TYPE_SERIALIZED:
273
273
  assert function_def.function_serialized or function_def.class_serialized
274
274
 
@@ -310,7 +310,7 @@ def main(container_args: api_pb2.ContainerArguments, client: Client):
310
310
  ser_usr_cls, ser_fun = get_serialized_user_class_and_function(function_def, _client)
311
311
 
312
312
  # Initialize the function, importing user code.
313
- with container_io_manager.handle_user_exception():
313
+ with container_io_manager.get_task_lifecycle_manager().handle_task_lifecycle_exception():
314
314
  if container_args.serialized_params:
315
315
  param_args, param_kwargs = deserialize_params(container_args.serialized_params, function_def, _client)
316
316
  else:
@@ -390,7 +390,7 @@ def main(container_args: api_pb2.ContainerArguments, client: Client):
390
390
  "that evaluates differently in the local and remote environments."
391
391
  )
392
392
  for object_id, obj in zip(dep_object_ids, service.service_deps):
393
- metadata: Optional[Message] = container_app.object_handle_metadata[object_id]
393
+ metadata: Message | None = container_app.object_handle_metadata[object_id]
394
394
  obj._hydrate(object_id, _client, metadata)
395
395
 
396
396
  # Initialize clustered functions.
@@ -401,7 +401,13 @@ def main(container_args: api_pb2.ContainerArguments, client: Client):
401
401
  function_def._experimental_group_size,
402
402
  )
403
403
 
404
- with service.execution_context(event_loop, container_io_manager) as finalized_functions:
404
+ with service.execution_context(
405
+ event_loop=event_loop,
406
+ snapshot=container_io_manager.memory_snapshot,
407
+ container_io_manager=container_io_manager,
408
+ ) as finalized_functions:
409
+ # This context managers handles pre/post snapshot lifecycle of the user code,
410
+ # finalized functions, ASGI/WSGI lifespan, and volume commit.
405
411
  if function_def.is_server:
406
412
  call_server(event_loop)
407
413
  else:
@@ -412,7 +418,7 @@ if __name__ == "__main__":
412
418
  logger.debug("Container: starting")
413
419
 
414
420
  container_args = api_pb2.ContainerArguments()
415
- container_arguments_path: Optional[str] = os.environ.get("MODAL_CONTAINER_ARGUMENTS_PATH")
421
+ container_arguments_path: str | None = os.environ.get("MODAL_CONTAINER_ARGUMENTS_PATH")
416
422
  if container_arguments_path is None:
417
423
  raise RuntimeError("No path to the container arguments file provided!")
418
424
  container_args.ParseFromString(open(container_arguments_path, "rb").read())
@@ -3,7 +3,7 @@ import asyncio
3
3
  import builtins
4
4
  from collections.abc import Iterable, Mapping
5
5
  from dataclasses import dataclass
6
- from typing import Literal, Optional
6
+ from typing import Literal
7
7
 
8
8
  from google.protobuf.empty_pb2 import Empty
9
9
  from google.protobuf.message import Message
@@ -35,7 +35,7 @@ class _EnvironmentManager:
35
35
  name: str, # Name to use for the new Environment
36
36
  *,
37
37
  restricted: bool = False, # If True, enable RBAC restrictions on the Environment
38
- client: Optional[_Client] = None, # Optional client with Modal credentials
38
+ client: _Client | None = None, # Optional client with Modal credentials
39
39
  ) -> None:
40
40
  """Create a new Environment.
41
41
 
@@ -52,7 +52,7 @@ class _EnvironmentManager:
52
52
  async def list(
53
53
  self,
54
54
  *,
55
- client: Optional[_Client] = None, # Optional client with Modal credentials
55
+ client: _Client | None = None, # Optional client with Modal credentials
56
56
  ) -> builtins.list["_Environment"]:
57
57
  """Return a list of hydrated Environment objects.
58
58
 
@@ -85,7 +85,7 @@ class _EnvironmentManager:
85
85
  self,
86
86
  name: str, # Name of the Environment to delete
87
87
  *,
88
- client: Optional[_Client] = None, # Optional client with Modal credentials
88
+ client: _Client | None = None, # Optional client with Modal credentials
89
89
  ) -> None:
90
90
  """Delete a named Environment.
91
91
 
@@ -116,9 +116,9 @@ def _role_to_proto(role: str) -> api_pb2.EnvironmentRole.ValueType:
116
116
 
117
117
  def _role_from_proto(proto_value: int) -> MemberRole:
118
118
  match proto_value:
119
- case int(v) if v == api_pb2.ENVIRONMENT_ROLE_VIEWER:
119
+ case api_pb2.ENVIRONMENT_ROLE_VIEWER:
120
120
  return "viewer"
121
- case int(v) if v == api_pb2.ENVIRONMENT_ROLE_CONTRIBUTOR:
121
+ case api_pb2.ENVIRONMENT_ROLE_CONTRIBUTOR:
122
122
  return "contributor"
123
123
  case _:
124
124
  raise ValueError(f"Unknown environment role: {proto_value}")
@@ -167,8 +167,8 @@ class _EnvironmentMembersManager:
167
167
  async def update(
168
168
  self,
169
169
  *,
170
- users: Optional[Mapping[str, MemberRole]] = None,
171
- service_users: Optional[Mapping[str, MemberRole]] = None,
170
+ users: Mapping[str, MemberRole] | None = None,
171
+ service_users: Mapping[str, MemberRole] | None = None,
172
172
  ) -> None:
173
173
  """Add or modify roles for members of a restricted Environment.
174
174
 
@@ -224,8 +224,8 @@ class _EnvironmentMembersManager:
224
224
  async def remove(
225
225
  self,
226
226
  *,
227
- users: Optional[Iterable[str]] = None,
228
- service_users: Optional[Iterable[str]] = None,
227
+ users: Iterable[str] | None = None,
228
+ service_users: Iterable[str] | None = None,
229
229
  ) -> None:
230
230
  """Remove members from a restricted Environment.
231
231
 
@@ -289,7 +289,7 @@ class _EnvironmentMembersManager:
289
289
 
290
290
 
291
291
  class _Environment(_Object, type_prefix="en"):
292
- _name: Optional[str] = None
292
+ _name: str | None = None
293
293
  _settings: EnvironmentSettings
294
294
 
295
295
  def __init__(self):
@@ -300,7 +300,7 @@ class _Environment(_Object, type_prefix="en"):
300
300
  )
301
301
 
302
302
  @property
303
- def name(self) -> Optional[str]:
303
+ def name(self) -> str | None:
304
304
  return self._name
305
305
 
306
306
  @classproperty
@@ -331,10 +331,10 @@ class _Environment(_Object, type_prefix="en"):
331
331
 
332
332
  @staticmethod
333
333
  def _get_or_create(
334
- name: str, repr: str, create_if_missing: bool = False, client: Optional[_Client] = None
334
+ name: str, repr: str, create_if_missing: bool = False, client: _Client | None = None
335
335
  ) -> "_Environment":
336
336
  async def _load(
337
- self: _Environment, resolver: Resolver, load_context: LoadContext, existing_object_id: Optional[str]
337
+ self: _Environment, resolver: Resolver, load_context: LoadContext, existing_object_id: str | None
338
338
  ):
339
339
  request = api_pb2.EnvironmentGetOrCreateRequest(
340
340
  deployment_name=name,
@@ -358,7 +358,7 @@ class _Environment(_Object, type_prefix="en"):
358
358
  )
359
359
 
360
360
  @staticmethod
361
- def from_context(*, client: Optional[_Client] = None) -> "_Environment":
361
+ def from_context(*, client: _Client | None = None) -> "_Environment":
362
362
  """Look up an Environment object using the current context.
363
363
 
364
364
  This method returns the Environment that is defined by the local configuration
@@ -381,7 +381,7 @@ class _Environment(_Object, type_prefix="en"):
381
381
  name: str,
382
382
  *,
383
383
  create_if_missing: bool = False,
384
- client: Optional[_Client] = None,
384
+ client: _Client | None = None,
385
385
  ) -> "_Environment":
386
386
  """Look up an Environment object using its name."""
387
387
  check_environment_name(name)
@@ -412,7 +412,7 @@ async def _get_environment_cached(name: str, client: _Client) -> _Environment:
412
412
  # and migrate users to the new object-oriented API, but that should happen gracefully.
413
413
 
414
414
 
415
- async def _delete_environment(name: str, client: Optional[_Client] = None):
415
+ async def _delete_environment(name: str, client: _Client | None = None):
416
416
  if client is None:
417
417
  client = await _Client.from_env()
418
418
  await client.stub.EnvironmentDelete(api_pb2.EnvironmentDeleteRequest(name=name))
@@ -421,9 +421,9 @@ async def _delete_environment(name: str, client: Optional[_Client] = None):
421
421
  async def _update_environment(
422
422
  current_name: str,
423
423
  *,
424
- new_name: Optional[str] = None,
425
- new_web_suffix: Optional[str] = None,
426
- client: Optional[_Client] = None,
424
+ new_name: str | None = None,
425
+ new_web_suffix: str | None = None,
426
+ client: _Client | None = None,
427
427
  ):
428
428
  new_name_pb2 = None
429
429
  new_web_suffix_pb2 = None
@@ -444,20 +444,20 @@ async def _update_environment(
444
444
  await client.stub.EnvironmentUpdate(update_payload)
445
445
 
446
446
 
447
- async def _create_environment(name: str, client: Optional[_Client] = None):
447
+ async def _create_environment(name: str, client: _Client | None = None):
448
448
  if client is None:
449
449
  client = await _Client.from_env()
450
450
  await client.stub.EnvironmentCreate(api_pb2.EnvironmentCreateRequest(name=name))
451
451
 
452
452
 
453
- async def _list_environments(client: Optional[_Client] = None) -> list[api_pb2.EnvironmentListItem]:
453
+ async def _list_environments(client: _Client | None = None) -> list[api_pb2.EnvironmentListItem]:
454
454
  if client is None:
455
455
  client = await _Client.from_env()
456
456
  resp = await client.stub.EnvironmentList(Empty())
457
457
  return list(resp.items)
458
458
 
459
459
 
460
- def ensure_env(environment_name: Optional[str] = None) -> str:
460
+ def ensure_env(environment_name: str | None = None) -> str:
461
461
  """Override config environment with environment from environment_name
462
462
 
463
463
  This is necessary since a cli command that runs Modal code, without explicit
@@ -2,7 +2,7 @@
2
2
  import dataclasses
3
3
  from collections.abc import Collection, Sequence, Sized
4
4
  from pathlib import PurePosixPath
5
- from typing import TYPE_CHECKING, Any, Optional, Union
5
+ from typing import TYPE_CHECKING, Any
6
6
 
7
7
  from modal_proto import api_pb2
8
8
 
@@ -39,40 +39,40 @@ class _FunctionOptions:
39
39
  secrets: Collection[_Secret] = ()
40
40
  validated_volumes: Sequence[tuple[str, _Volume]] = ()
41
41
  cloud_bucket_mounts: Sequence[tuple[str, _CloudBucketMount]] = ()
42
- resources: Optional[api_pb2.Resources] = None
43
- retry_policy: Optional[api_pb2.FunctionRetryPolicy] = None
44
- max_containers: Optional[int] = None
45
- buffer_containers: Optional[int] = None
46
- scaledown_window: Optional[int] = None
47
- timeout_secs: Optional[int] = None
48
- scheduler_placement: Optional[api_pb2.SchedulerPlacement] = None
49
- cloud: Optional[str] = None
50
- max_concurrent_inputs: Optional[int] = None
51
- target_concurrent_inputs: Optional[int] = None
52
- batch_max_size: Optional[int] = None
53
- batch_wait_ms: Optional[int] = None
42
+ resources: api_pb2.Resources | None = None
43
+ retry_policy: api_pb2.FunctionRetryPolicy | None = None
44
+ max_containers: int | None = None
45
+ buffer_containers: int | None = None
46
+ scaledown_window: int | None = None
47
+ timeout_secs: int | None = None
48
+ scheduler_placement: api_pb2.SchedulerPlacement | None = None
49
+ cloud: str | None = None
50
+ max_concurrent_inputs: int | None = None
51
+ target_concurrent_inputs: int | None = None
52
+ batch_max_size: int | None = None
53
+ batch_wait_ms: int | None = None
54
54
 
55
55
  @classmethod
56
56
  def new(
57
57
  cls,
58
58
  *,
59
- cpu: Optional[Union[float, tuple[float, float]]] = None,
60
- memory: Optional[Union[int, tuple[int, int]]] = None,
61
- gpu: Optional[str] = None,
62
- env: Optional[dict[str, Optional[str]]] = None,
63
- secrets: Optional[Collection[_Secret]] = None,
64
- volumes: dict[Union[str, PurePosixPath], Union[_Volume, _CloudBucketMount]] = {},
65
- retries: Optional[Union[int, Retries]] = None,
66
- max_containers: Optional[int] = None,
67
- buffer_containers: Optional[int] = None,
68
- scaledown_window: Optional[int] = None,
69
- timeout: Optional[int] = None,
70
- region: Optional[Union[str, Sequence[str]]] = None,
71
- cloud: Optional[str] = None,
72
- max_concurrent_inputs: Optional[int] = None,
73
- target_concurrent_inputs: Optional[int] = None,
74
- batch_max_size: Optional[int] = None,
75
- batch_wait_ms: Optional[int] = None,
59
+ cpu: float | tuple[float, float] | None = None,
60
+ memory: int | tuple[int, int] | None = None,
61
+ gpu: str | None = None,
62
+ env: dict[str, str | None] | None = None,
63
+ secrets: Collection[_Secret] | None = None,
64
+ volumes: dict[str | PurePosixPath, _Volume | _CloudBucketMount] = {},
65
+ retries: int | Retries | None = None,
66
+ max_containers: int | None = None,
67
+ buffer_containers: int | None = None,
68
+ scaledown_window: int | None = None,
69
+ timeout: int | None = None,
70
+ region: str | Sequence[str] | None = None,
71
+ cloud: str | None = None,
72
+ max_concurrent_inputs: int | None = None,
73
+ target_concurrent_inputs: int | None = None,
74
+ batch_max_size: int | None = None,
75
+ batch_wait_ms: int | None = None,
76
76
  ) -> "_FunctionOptions":
77
77
  """Internal constructor that validates and normalizes public parameters."""
78
78
  retry_policy = _parse_retries(retries)
@@ -89,7 +89,7 @@ class _FunctionOptions:
89
89
  if env:
90
90
  secrets = [*secrets, _Secret.from_dict(env)]
91
91
 
92
- scheduler_placement: Optional[api_pb2.SchedulerPlacement] = None
92
+ scheduler_placement: api_pb2.SchedulerPlacement | None = None
93
93
  if region:
94
94
  regions = [region] if isinstance(region, str) else list(region)
95
95
  scheduler_placement = api_pb2.SchedulerPlacement(regions=regions)
@@ -187,8 +187,8 @@ class _FunctionOptions:
187
187
 
188
188
  def _make_function_variant(
189
189
  base_function: "_Function",
190
- options: Optional[_FunctionOptions],
191
- parameter_schema: Optional[Sequence[api_pb2.ClassParameterSpec]],
190
+ options: _FunctionOptions | None,
191
+ parameter_schema: Sequence[api_pb2.ClassParameterSpec] | None,
192
192
  args: Sized,
193
193
  kwargs: dict[str, Any],
194
194
  ) -> "_Function":
@@ -198,7 +198,7 @@ def _make_function_variant(
198
198
  function_variant: "_Function",
199
199
  resolver: "Resolver",
200
200
  load_context: "LoadContext",
201
- existing_object_id: Optional[str],
201
+ existing_object_id: str | None,
202
202
  ):
203
203
  if not base_function.is_hydrated:
204
204
  await base_function.hydrate(load_context.client)