modAL 1.2.5.dev6__tar.gz → 1.2.5.dev8__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (202) hide show
  1. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/PKG-INFO +1 -1
  2. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_runtime/user_code_imports.py +95 -77
  3. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/client.pyi +2 -2
  4. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/functions.pyi +6 -6
  5. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/io_streams.py +7 -6
  6. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal.egg-info/PKG-INFO +1 -1
  7. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal_version/__init__.py +1 -1
  8. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/LICENSE +0 -0
  9. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/README.md +0 -0
  10. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/__init__.py +0 -0
  11. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/__main__.py +0 -0
  12. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_billing.py +0 -0
  13. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_clustered_functions.py +0 -0
  14. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_clustered_functions.pyi +0 -0
  15. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_container_entrypoint.py +0 -0
  16. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_functions.py +0 -0
  17. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_grpc_client.py +0 -0
  18. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_ipython.py +0 -0
  19. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_load_context.py +0 -0
  20. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_location.py +0 -0
  21. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_object.py +0 -0
  22. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_output.py +0 -0
  23. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_partial_function.py +0 -0
  24. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_pty.py +0 -0
  25. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_resolver.py +0 -0
  26. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_resources.py +0 -0
  27. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_runtime/__init__.py +0 -0
  28. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_runtime/asgi.py +0 -0
  29. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_runtime/container_io_manager.py +0 -0
  30. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_runtime/container_io_manager.pyi +0 -0
  31. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_runtime/execution_context.py +0 -0
  32. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_runtime/execution_context.pyi +0 -0
  33. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_runtime/gpu_memory_snapshot.py +0 -0
  34. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_runtime/telemetry.py +0 -0
  35. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_runtime/user_code_event_loop.py +0 -0
  36. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_serialization.py +0 -0
  37. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_traceback.py +0 -0
  38. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_tunnel.py +0 -0
  39. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_tunnel.pyi +0 -0
  40. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_type_manager.py +0 -0
  41. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_utils/__init__.py +0 -0
  42. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_utils/app_utils.py +0 -0
  43. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_utils/async_utils.py +0 -0
  44. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_utils/auth_token_manager.py +0 -0
  45. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_utils/blob_utils.py +0 -0
  46. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_utils/bytes_io_segment_payload.py +0 -0
  47. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_utils/deprecation.py +0 -0
  48. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_utils/docker_utils.py +0 -0
  49. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_utils/function_utils.py +0 -0
  50. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_utils/git_utils.py +0 -0
  51. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_utils/grpc_testing.py +0 -0
  52. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_utils/grpc_utils.py +0 -0
  53. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_utils/hash_utils.py +0 -0
  54. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_utils/http_utils.py +0 -0
  55. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_utils/jwt_utils.py +0 -0
  56. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_utils/logger.py +0 -0
  57. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_utils/mount_utils.py +0 -0
  58. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_utils/name_utils.py +0 -0
  59. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_utils/package_utils.py +0 -0
  60. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_utils/pattern_utils.py +0 -0
  61. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_utils/rand_pb_testing.py +0 -0
  62. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_utils/shell_utils.py +0 -0
  63. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_utils/task_command_router_client.py +0 -0
  64. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_utils/time_utils.py +0 -0
  65. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_vendor/__init__.py +0 -0
  66. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_vendor/a2wsgi_wsgi.py +0 -0
  67. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_vendor/cloudpickle.py +0 -0
  68. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_vendor/tblib.py +0 -0
  69. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/_watcher.py +0 -0
  70. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/app.py +0 -0
  71. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/app.pyi +0 -0
  72. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/billing.py +0 -0
  73. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/builder/2023.12.312.txt +0 -0
  74. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/builder/2023.12.txt +0 -0
  75. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/builder/2024.04.txt +0 -0
  76. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/builder/2024.10.txt +0 -0
  77. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/builder/2025.06.txt +0 -0
  78. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/builder/PREVIEW.txt +0 -0
  79. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/builder/README.md +0 -0
  80. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/builder/base-images.json +0 -0
  81. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/call_graph.py +0 -0
  82. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/cli/__init__.py +0 -0
  83. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/cli/_download.py +0 -0
  84. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/cli/_traceback.py +0 -0
  85. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/cli/app.py +0 -0
  86. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/cli/cluster.py +0 -0
  87. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/cli/config.py +0 -0
  88. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/cli/container.py +0 -0
  89. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/cli/dict.py +0 -0
  90. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/cli/entry_point.py +0 -0
  91. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/cli/environment.py +0 -0
  92. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/cli/import_refs.py +0 -0
  93. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/cli/launch.py +0 -0
  94. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/cli/network_file_system.py +0 -0
  95. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/cli/profile.py +0 -0
  96. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/cli/programs/__init__.py +0 -0
  97. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/cli/programs/launch_instance_ssh.py +0 -0
  98. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/cli/programs/run_jupyter.py +0 -0
  99. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/cli/programs/run_marimo.py +0 -0
  100. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/cli/programs/vscode.py +0 -0
  101. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/cli/queues.py +0 -0
  102. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/cli/run.py +0 -0
  103. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/cli/secret.py +0 -0
  104. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/cli/shell.py +0 -0
  105. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/cli/token.py +0 -0
  106. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/cli/utils.py +0 -0
  107. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/cli/volume.py +0 -0
  108. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/client.py +0 -0
  109. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/cloud_bucket_mount.py +0 -0
  110. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/cloud_bucket_mount.pyi +0 -0
  111. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/cls.py +0 -0
  112. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/cls.pyi +0 -0
  113. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/config.py +0 -0
  114. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/container_process.py +0 -0
  115. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/container_process.pyi +0 -0
  116. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/dict.py +0 -0
  117. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/dict.pyi +0 -0
  118. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/environments.py +0 -0
  119. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/environments.pyi +0 -0
  120. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/exception.py +0 -0
  121. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/experimental/__init__.py +0 -0
  122. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/experimental/flash.py +0 -0
  123. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/experimental/flash.pyi +0 -0
  124. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/experimental/ipython.py +0 -0
  125. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/file_io.py +0 -0
  126. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/file_io.pyi +0 -0
  127. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/file_pattern_matcher.py +0 -0
  128. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/functions.py +0 -0
  129. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/gpu.py +0 -0
  130. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/image.py +0 -0
  131. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/image.pyi +0 -0
  132. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/io_streams.pyi +0 -0
  133. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/mount.py +0 -0
  134. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/mount.pyi +0 -0
  135. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/network_file_system.py +0 -0
  136. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/network_file_system.pyi +0 -0
  137. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/object.py +0 -0
  138. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/object.pyi +0 -0
  139. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/output.py +0 -0
  140. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/parallel_map.py +0 -0
  141. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/parallel_map.pyi +0 -0
  142. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/partial_function.py +0 -0
  143. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/partial_function.pyi +0 -0
  144. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/proxy.py +0 -0
  145. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/proxy.pyi +0 -0
  146. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/py.typed +0 -0
  147. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/queue.py +0 -0
  148. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/queue.pyi +0 -0
  149. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/retries.py +0 -0
  150. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/runner.py +0 -0
  151. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/runner.pyi +0 -0
  152. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/running_app.py +0 -0
  153. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/sandbox.py +0 -0
  154. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/sandbox.pyi +0 -0
  155. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/schedule.py +0 -0
  156. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/scheduler_placement.py +0 -0
  157. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/secret.py +0 -0
  158. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/secret.pyi +0 -0
  159. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/serving.py +0 -0
  160. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/serving.pyi +0 -0
  161. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/snapshot.py +0 -0
  162. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/snapshot.pyi +0 -0
  163. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/stream_type.py +0 -0
  164. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/token_flow.py +0 -0
  165. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/token_flow.pyi +0 -0
  166. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/volume.py +0 -0
  167. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal/volume.pyi +0 -0
  168. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal.egg-info/SOURCES.txt +0 -0
  169. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal.egg-info/dependency_links.txt +0 -0
  170. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal.egg-info/entry_points.txt +0 -0
  171. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal.egg-info/requires.txt +0 -0
  172. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal.egg-info/top_level.txt +0 -0
  173. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal_docs/__init__.py +0 -0
  174. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal_docs/gen_cli_docs.py +0 -0
  175. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal_docs/gen_reference_docs.py +0 -0
  176. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal_docs/mdmd/__init__.py +0 -0
  177. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal_docs/mdmd/mdmd.py +0 -0
  178. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal_docs/mdmd/signatures.py +0 -0
  179. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal_proto/__init__.py +0 -0
  180. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal_proto/api.proto +0 -0
  181. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal_proto/api_grpc.py +0 -0
  182. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal_proto/api_pb2.py +0 -0
  183. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal_proto/api_pb2.pyi +0 -0
  184. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal_proto/api_pb2_grpc.py +0 -0
  185. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal_proto/api_pb2_grpc.pyi +0 -0
  186. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal_proto/modal_api_grpc.py +0 -0
  187. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal_proto/py.typed +0 -0
  188. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal_proto/sandbox_router.proto +0 -0
  189. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal_proto/sandbox_router_grpc.py +0 -0
  190. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal_proto/sandbox_router_pb2.py +0 -0
  191. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal_proto/sandbox_router_pb2.pyi +0 -0
  192. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal_proto/sandbox_router_pb2_grpc.py +0 -0
  193. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal_proto/sandbox_router_pb2_grpc.pyi +0 -0
  194. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal_proto/task_command_router.proto +0 -0
  195. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal_proto/task_command_router_grpc.py +0 -0
  196. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal_proto/task_command_router_pb2.py +0 -0
  197. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal_proto/task_command_router_pb2.pyi +0 -0
  198. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal_proto/task_command_router_pb2_grpc.py +0 -0
  199. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal_proto/task_command_router_pb2_grpc.pyi +0 -0
  200. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/modal_version/__main__.py +0 -0
  201. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/pyproject.toml +0 -0
  202. {modal-1.2.5.dev6 → modal-1.2.5.dev8}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.2.5.dev6
3
+ Version: 1.2.5.dev8
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License: Apache-2.0
@@ -64,12 +64,10 @@ def call_lifecycle_functions(
64
64
 
65
65
 
66
66
  @contextmanager
67
- def _run_service_lifecycle(
67
+ def lifecycle_asgi(
68
68
  event_loop: UserCodeEventLoop,
69
69
  container_io_manager: "modal._runtime.container_io_manager.ContainerIOManager",
70
- function_def: api_pb2.Function,
71
70
  finalized_functions: dict[str, FinalizedFunction],
72
- exit_callback: Optional[Callable[[], None]],
73
71
  ) -> Generator[None, None, None]:
74
72
  lifespan_background_tasks = []
75
73
  try:
@@ -82,38 +80,34 @@ def _run_service_lifecycle(
82
80
  event_loop.run(finalized_function.lifespan_manager.lifespan_startup())
83
81
  yield
84
82
  finally:
85
- # Run exit handlers. From this point onward, ignore all SIGINT signals that come from
86
- # graceful shutdowns originating on the worker, as well as stray SIGUSR1 signals that
87
- # may have been sent to cancel inputs.
88
- int_handler = signal.signal(signal.SIGINT, signal.SIG_IGN)
89
- usr1_handler = signal.signal(signal.SIGUSR1, signal.SIG_IGN)
90
83
  try:
91
- try:
92
- # run lifespan shutdown for asgi apps
93
- for finalized_function in finalized_functions.values():
94
- if finalized_function.lifespan_manager:
95
- with container_io_manager.handle_user_exception():
96
- event_loop.run(finalized_function.lifespan_manager.lifespan_shutdown())
97
- finally:
98
- # no need to keep the lifespan asgi call around - we send it no more messages
99
- for task in lifespan_background_tasks:
100
- task.cancel()
101
-
102
- # Identify "exit" methods and run them.
103
- # want to make sure this is called even if the lifespan manager fails
104
- if exit_callback:
105
- exit_callback()
106
-
107
- # Finally, commit on exit to catch uncommitted volume changes and surface background
108
- # commit errors.
109
- container_io_manager.volume_commit(
110
- [v.volume_id for v in function_def.volume_mounts if v.allow_background_commits]
111
- )
84
+ # run lifespan shutdown for asgi apps
85
+ for finalized_function in finalized_functions.values():
86
+ if finalized_function.lifespan_manager:
87
+ with container_io_manager.handle_user_exception():
88
+ event_loop.run(finalized_function.lifespan_manager.lifespan_shutdown())
112
89
  finally:
113
- # Restore the original signal handler, needed for container_test hygiene since the
114
- # test runs `main()` multiple times in the same process.
115
- signal.signal(signal.SIGINT, int_handler)
116
- signal.signal(signal.SIGUSR1, usr1_handler)
90
+ # no need to keep the lifespan asgi call around - we send it no more messages
91
+ for task in lifespan_background_tasks:
92
+ task.cancel()
93
+
94
+
95
+ def disable_signals():
96
+ int_handler = signal.signal(signal.SIGINT, signal.SIG_IGN)
97
+ usr1_handler = signal.signal(signal.SIGUSR1, signal.SIG_IGN)
98
+ return int_handler, usr1_handler
99
+
100
+
101
+ def try_enable_signals(int_handler, usr1_handler):
102
+ if int_handler is not None and usr1_handler is not None:
103
+ signal.signal(signal.SIGINT, int_handler)
104
+ signal.signal(signal.SIGUSR1, usr1_handler)
105
+
106
+
107
+ def volume_commit(
108
+ container_io_manager: "modal._runtime.container_io_manager.ContainerIOManager", function_def: api_pb2.Function
109
+ ):
110
+ container_io_manager.volume_commit([v.volume_id for v in function_def.volume_mounts if v.allow_background_commits])
117
111
 
118
112
 
119
113
  class Service(metaclass=ABCMeta):
@@ -127,14 +121,30 @@ class Service(metaclass=ABCMeta):
127
121
  user_cls_instance: Any
128
122
  app: "modal.app._App"
129
123
  service_deps: Optional[Sequence["modal._object._Object"]]
124
+ function_def: api_pb2.Function
130
125
 
131
126
  @abstractmethod
132
127
  def get_finalized_functions(
133
128
  self, fun_def: api_pb2.Function, container_io_manager: "modal._runtime.container_io_manager.ContainerIOManager"
134
129
  ) -> dict[str, "FinalizedFunction"]: ...
135
130
 
131
+ @abstractmethod
136
132
  @contextmanager
133
+ def lifecycle_presnapshot(
134
+ self,
135
+ event_loop: UserCodeEventLoop,
136
+ container_io_manager: "modal._runtime.container_io_manager.ContainerIOManager",
137
+ ) -> Generator[None, None, None]: ...
138
+
137
139
  @abstractmethod
140
+ @contextmanager
141
+ def lifecycle_postsnapshot(
142
+ self,
143
+ event_loop: UserCodeEventLoop,
144
+ container_io_manager: "modal._runtime.container_io_manager.ContainerIOManager",
145
+ ) -> Generator[None, None, None]: ...
146
+
147
+ @contextmanager
138
148
  def execution_context(
139
149
  self,
140
150
  event_loop: UserCodeEventLoop,
@@ -150,6 +160,34 @@ class Service(metaclass=ABCMeta):
150
160
  6. Yield finalized_functions for execution
151
161
  7. Handles cleanup (lifespan shutdown, 'exit' methods)
152
162
  """
163
+ int_handler, usr1_handler = None, None
164
+ try:
165
+ # 1. Pre-snapshot Enter
166
+ with self.lifecycle_presnapshot(event_loop, container_io_manager):
167
+ # 2. Snapshot -- If this container is being used to create a checkpoint, checkpoint the container after
168
+ # global imports and initialization. Checkpointed containers run from this point onwards.
169
+ maybe_snapshot(container_io_manager, self.function_def)
170
+ # 3. Breakpoint wrapper
171
+ create_breakpoint_wrapper(container_io_manager)
172
+ # 4. Post-snapshot Enter
173
+ with self.lifecycle_postsnapshot(event_loop, container_io_manager):
174
+ # Get Functions
175
+ with container_io_manager.handle_user_exception():
176
+ finalized_functions = self.get_finalized_functions(self.function_def, container_io_manager)
177
+ # 5. Start ASGI lifespan
178
+ with lifecycle_asgi(event_loop, container_io_manager, finalized_functions):
179
+ # 6. Yield Finalized Functions
180
+ try:
181
+ yield finalized_functions
182
+ finally:
183
+ int_handler, usr1_handler = disable_signals()
184
+ finally:
185
+ # 9. Volume commit - runs OUTSIDE all lifecycle managers so exit handlers
186
+ # have a chance to write to disk before we commit volumes
187
+ try:
188
+ volume_commit(container_io_manager, self.function_def)
189
+ finally:
190
+ try_enable_signals(int_handler, usr1_handler)
153
191
 
154
192
 
155
193
  def construct_webhook_callable(
@@ -265,27 +303,22 @@ class ImportedFunction(Service):
265
303
  }
266
304
 
267
305
  @contextmanager
268
- def execution_context(
306
+ def lifecycle_presnapshot(
269
307
  self,
270
308
  event_loop: UserCodeEventLoop,
271
309
  container_io_manager: "modal._runtime.container_io_manager.ContainerIOManager",
272
- ) -> Generator[dict[str, "FinalizedFunction"], None, None]:
273
- # If this container is being used to create a checkpoint, checkpoint the container after
274
- # global imports and initialization. Checkpointed containers run from this point onwards.
275
- maybe_snapshot(container_io_manager, self.function_def)
276
- create_breakpoint_wrapper(container_io_manager)
277
-
278
- with container_io_manager.handle_user_exception():
279
- finalized_functions = self.get_finalized_functions(self.function_def, container_io_manager)
310
+ ):
311
+ # This is a no-op for imported functions since @enter methods are not supported
312
+ yield
280
313
 
281
- with _run_service_lifecycle(
282
- event_loop,
283
- container_io_manager,
284
- self.function_def,
285
- finalized_functions,
286
- None,
287
- ):
288
- yield finalized_functions
314
+ @contextmanager
315
+ def lifecycle_postsnapshot(
316
+ self,
317
+ event_loop: UserCodeEventLoop,
318
+ container_io_manager: "modal._runtime.container_io_manager.ContainerIOManager",
319
+ ):
320
+ # This is a no-op for imported functions since @enter methods are not supported
321
+ yield
289
322
 
290
323
 
291
324
  @dataclass
@@ -340,53 +373,38 @@ class ImportedClass(Service):
340
373
  return finalized_functions
341
374
 
342
375
  @contextmanager
343
- def execution_context(
376
+ def lifecycle_presnapshot(
344
377
  self,
345
378
  event_loop: UserCodeEventLoop,
346
379
  container_io_manager: "modal._runtime.container_io_manager.ContainerIOManager",
347
- ) -> Generator[dict[str, "FinalizedFunction"], None, None]:
348
- # 1. Pre-snapshot Enter
380
+ ):
349
381
  # Identify all "enter" methods that need to run before we snapshot.
350
382
  if not self.function_def.is_auto_snapshot:
351
383
  pre_snapshot_methods = _find_callables_for_obj(
352
384
  self.user_cls_instance, _PartialFunctionFlags.ENTER_PRE_SNAPSHOT
353
385
  )
354
386
  call_lifecycle_functions(event_loop, container_io_manager, list(pre_snapshot_methods.values()))
387
+ yield
355
388
 
356
- # 2. Snapshot
357
- # If this container is being used to create a checkpoint, checkpoint the container after
358
- # global imports and initialization. Checkpointed containers run from this point onwards.
359
- maybe_snapshot(container_io_manager, self.function_def)
360
-
361
- # 3. Breakpoint wrapper
362
- create_breakpoint_wrapper(container_io_manager)
363
-
364
- # 4. Post-snapshot Enter
389
+ @contextmanager
390
+ def lifecycle_postsnapshot(
391
+ self,
392
+ event_loop: UserCodeEventLoop,
393
+ container_io_manager: "modal._runtime.container_io_manager.ContainerIOManager",
394
+ ):
365
395
  # Identify the "enter" methods to run after resuming from a snapshot.
366
396
  if not self.function_def.is_auto_snapshot:
367
397
  post_snapshot_methods = _find_callables_for_obj(
368
398
  self.user_cls_instance, _PartialFunctionFlags.ENTER_POST_SNAPSHOT
369
399
  )
370
400
  call_lifecycle_functions(event_loop, container_io_manager, list(post_snapshot_methods.values()))
371
-
372
- # 5. Get Functions & Start Lifespan
373
- with container_io_manager.handle_user_exception():
374
- finalized_functions = self.get_finalized_functions(self.function_def, container_io_manager)
375
-
376
- def exit_callback():
401
+ try:
402
+ yield
403
+ finally:
377
404
  if not self.function_def.is_auto_snapshot:
378
405
  exit_methods = _find_callables_for_obj(self.user_cls_instance, _PartialFunctionFlags.EXIT)
379
406
  call_lifecycle_functions(event_loop, container_io_manager, list(exit_methods.values()))
380
407
 
381
- with _run_service_lifecycle(
382
- event_loop,
383
- container_io_manager,
384
- self.function_def,
385
- finalized_functions,
386
- exit_callback,
387
- ):
388
- yield finalized_functions
389
-
390
408
 
391
409
  def get_user_class_instance(_cls: modal.cls._Cls, args: tuple[Any, ...], kwargs: dict[str, Any]) -> typing.Any:
392
410
  """Returns instance of the underlying class to be used as the `self`
@@ -32,7 +32,7 @@ class _Client:
32
32
  server_url: str,
33
33
  client_type: int,
34
34
  credentials: typing.Optional[tuple[str, str]],
35
- version: str = "1.2.5.dev6",
35
+ version: str = "1.2.5.dev8",
36
36
  ):
37
37
  """mdmd:hidden
38
38
  The Modal client object is not intended to be instantiated directly by users.
@@ -163,7 +163,7 @@ class Client:
163
163
  server_url: str,
164
164
  client_type: int,
165
165
  credentials: typing.Optional[tuple[str, str]],
166
- version: str = "1.2.5.dev6",
166
+ version: str = "1.2.5.dev8",
167
167
  ):
168
168
  """mdmd:hidden
169
169
  The Modal client object is not intended to be instantiated directly by users.
@@ -408,7 +408,7 @@ class Function(
408
408
 
409
409
  _call_generator: ___call_generator_spec[typing_extensions.Self]
410
410
 
411
- class __remote_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER, SUPERSELF]):
411
+ class __remote_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER, SUPERSELF]):
412
412
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> ReturnType_INNER:
413
413
  """Calls the function remotely, executing it with the given arguments and returning the execution's result."""
414
414
  ...
@@ -417,7 +417,7 @@ class Function(
417
417
  """Calls the function remotely, executing it with the given arguments and returning the execution's result."""
418
418
  ...
419
419
 
420
- remote: __remote_spec[modal._functions.P, modal._functions.ReturnType, typing_extensions.Self]
420
+ remote: __remote_spec[modal._functions.ReturnType, modal._functions.P, typing_extensions.Self]
421
421
 
422
422
  class __remote_gen_spec(typing_extensions.Protocol[SUPERSELF]):
423
423
  def __call__(self, /, *args, **kwargs) -> typing.Generator[typing.Any, None, None]:
@@ -444,7 +444,7 @@ class Function(
444
444
  """
445
445
  ...
446
446
 
447
- class ___experimental_spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER, SUPERSELF]):
447
+ class ___experimental_spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER, SUPERSELF]):
448
448
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
449
449
  """[Experimental] Calls the function with the given arguments, without waiting for the results.
450
450
 
@@ -468,7 +468,7 @@ class Function(
468
468
  ...
469
469
 
470
470
  _experimental_spawn: ___experimental_spawn_spec[
471
- modal._functions.P, modal._functions.ReturnType, typing_extensions.Self
471
+ modal._functions.ReturnType, modal._functions.P, typing_extensions.Self
472
472
  ]
473
473
 
474
474
  class ___spawn_map_inner_spec(typing_extensions.Protocol[P_INNER, SUPERSELF]):
@@ -477,7 +477,7 @@ class Function(
477
477
 
478
478
  _spawn_map_inner: ___spawn_map_inner_spec[modal._functions.P, typing_extensions.Self]
479
479
 
480
- class __spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER, SUPERSELF]):
480
+ class __spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER, SUPERSELF]):
481
481
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
482
482
  """Calls the function with the given arguments, without waiting for the results.
483
483
 
@@ -498,7 +498,7 @@ class Function(
498
498
  """
499
499
  ...
500
500
 
501
- spawn: __spawn_spec[modal._functions.P, modal._functions.ReturnType, typing_extensions.Self]
501
+ spawn: __spawn_spec[modal._functions.ReturnType, modal._functions.P, typing_extensions.Self]
502
502
 
503
503
  def get_raw_f(self) -> collections.abc.Callable[..., typing.Any]:
504
504
  """Return the inner Python object wrapped by this Modal Function."""
@@ -2,6 +2,7 @@
2
2
  import asyncio
3
3
  import codecs
4
4
  import contextlib
5
+ import io
5
6
  import sys
6
7
  import time
7
8
  from collections.abc import AsyncGenerator, AsyncIterator
@@ -403,10 +404,10 @@ class _BytesStreamReaderThroughCommandRouter:
403
404
  return self._params.file_descriptor
404
405
 
405
406
  async def read(self) -> bytes:
406
- data_bytes = b""
407
+ buffer = io.BytesIO()
407
408
  async for part in self:
408
- data_bytes += cast(bytes, part)
409
- return data_bytes
409
+ buffer.write(part)
410
+ return buffer.getvalue()
410
411
 
411
412
  def __aiter__(self) -> AsyncGenerator[bytes, None]:
412
413
  return _stdio_stream_from_command_router(self._params)
@@ -438,10 +439,10 @@ class _TextStreamReaderThroughCommandRouter:
438
439
  return self._params.file_descriptor
439
440
 
440
441
  async def read(self) -> str:
441
- data_str = ""
442
+ buffer = io.StringIO()
442
443
  async for part in self:
443
- data_str += cast(str, part)
444
- return data_str
444
+ buffer.write(part)
445
+ return buffer.getvalue()
445
446
 
446
447
  async def __aiter__(self) -> AsyncGenerator[str, None]:
447
448
  async with aclosing(_stdio_stream_from_command_router(self._params)) as bytes_stream:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.2.5.dev6
3
+ Version: 1.2.5.dev8
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License: Apache-2.0
@@ -1,4 +1,4 @@
1
1
  # Copyright Modal Labs 2025
2
2
  """Supplies the current version of the modal client library."""
3
3
 
4
- __version__ = "1.2.5.dev6"
4
+ __version__ = "1.2.5.dev8"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes