modal 1.1.2.dev37__tar.gz → 1.1.2.dev39__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 (190) hide show
  1. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/PKG-INFO +1 -1
  2. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/_container_entrypoint.py +6 -0
  3. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/_functions.py +1 -1
  4. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/_runtime/asgi.py +3 -2
  5. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/_runtime/container_io_manager.py +9 -4
  6. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/_runtime/container_io_manager.pyi +32 -9
  7. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/_utils/function_utils.py +4 -3
  8. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/client.pyi +2 -2
  9. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/functions.pyi +6 -6
  10. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal.egg-info/PKG-INFO +1 -1
  11. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal_version/__init__.py +1 -1
  12. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/LICENSE +0 -0
  13. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/README.md +0 -0
  14. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/__init__.py +0 -0
  15. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/__main__.py +0 -0
  16. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/_clustered_functions.py +0 -0
  17. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/_clustered_functions.pyi +0 -0
  18. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/_ipython.py +0 -0
  19. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/_location.py +0 -0
  20. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/_object.py +0 -0
  21. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/_output.py +0 -0
  22. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/_partial_function.py +0 -0
  23. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/_pty.py +0 -0
  24. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/_resolver.py +0 -0
  25. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/_resources.py +0 -0
  26. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/_runtime/__init__.py +0 -0
  27. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/_runtime/execution_context.py +0 -0
  28. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/_runtime/execution_context.pyi +0 -0
  29. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/_runtime/gpu_memory_snapshot.py +0 -0
  30. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/_runtime/telemetry.py +0 -0
  31. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/_runtime/user_code_imports.py +0 -0
  32. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/_serialization.py +0 -0
  33. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/_traceback.py +0 -0
  34. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/_tunnel.py +0 -0
  35. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/_tunnel.pyi +0 -0
  36. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/_type_manager.py +0 -0
  37. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/_utils/__init__.py +0 -0
  38. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/_utils/app_utils.py +0 -0
  39. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/_utils/async_utils.py +0 -0
  40. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/_utils/auth_token_manager.py +0 -0
  41. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/_utils/blob_utils.py +0 -0
  42. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/_utils/bytes_io_segment_payload.py +0 -0
  43. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/_utils/deprecation.py +0 -0
  44. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/_utils/docker_utils.py +0 -0
  45. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/_utils/git_utils.py +0 -0
  46. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/_utils/grpc_testing.py +0 -0
  47. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/_utils/grpc_utils.py +0 -0
  48. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/_utils/hash_utils.py +0 -0
  49. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/_utils/http_utils.py +0 -0
  50. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/_utils/jwt_utils.py +0 -0
  51. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/_utils/logger.py +0 -0
  52. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/_utils/mount_utils.py +0 -0
  53. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/_utils/name_utils.py +0 -0
  54. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/_utils/package_utils.py +0 -0
  55. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/_utils/pattern_utils.py +0 -0
  56. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/_utils/rand_pb_testing.py +0 -0
  57. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/_utils/shell_utils.py +0 -0
  58. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/_utils/time_utils.py +0 -0
  59. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/_vendor/__init__.py +0 -0
  60. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/_vendor/a2wsgi_wsgi.py +0 -0
  61. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/_vendor/cloudpickle.py +0 -0
  62. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/_vendor/tblib.py +0 -0
  63. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/_watcher.py +0 -0
  64. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/app.py +0 -0
  65. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/app.pyi +0 -0
  66. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/builder/2023.12.312.txt +0 -0
  67. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/builder/2023.12.txt +0 -0
  68. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/builder/2024.04.txt +0 -0
  69. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/builder/2024.10.txt +0 -0
  70. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/builder/2025.06.txt +0 -0
  71. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/builder/PREVIEW.txt +0 -0
  72. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/builder/README.md +0 -0
  73. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/builder/base-images.json +0 -0
  74. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/call_graph.py +0 -0
  75. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/cli/__init__.py +0 -0
  76. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/cli/_download.py +0 -0
  77. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/cli/_traceback.py +0 -0
  78. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/cli/app.py +0 -0
  79. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/cli/cluster.py +0 -0
  80. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/cli/config.py +0 -0
  81. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/cli/container.py +0 -0
  82. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/cli/dict.py +0 -0
  83. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/cli/entry_point.py +0 -0
  84. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/cli/environment.py +0 -0
  85. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/cli/import_refs.py +0 -0
  86. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/cli/launch.py +0 -0
  87. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/cli/network_file_system.py +0 -0
  88. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/cli/profile.py +0 -0
  89. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/cli/programs/__init__.py +0 -0
  90. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/cli/programs/launch_instance_ssh.py +0 -0
  91. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/cli/programs/run_jupyter.py +0 -0
  92. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/cli/programs/run_marimo.py +0 -0
  93. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/cli/programs/vscode.py +0 -0
  94. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/cli/queues.py +0 -0
  95. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/cli/run.py +0 -0
  96. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/cli/secret.py +0 -0
  97. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/cli/token.py +0 -0
  98. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/cli/utils.py +0 -0
  99. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/cli/volume.py +0 -0
  100. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/client.py +0 -0
  101. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/cloud_bucket_mount.py +0 -0
  102. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/cloud_bucket_mount.pyi +0 -0
  103. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/cls.py +0 -0
  104. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/cls.pyi +0 -0
  105. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/config.py +0 -0
  106. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/container_process.py +0 -0
  107. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/container_process.pyi +0 -0
  108. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/dict.py +0 -0
  109. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/dict.pyi +0 -0
  110. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/environments.py +0 -0
  111. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/environments.pyi +0 -0
  112. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/exception.py +0 -0
  113. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/experimental/__init__.py +0 -0
  114. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/experimental/flash.py +0 -0
  115. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/experimental/flash.pyi +0 -0
  116. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/experimental/ipython.py +0 -0
  117. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/file_io.py +0 -0
  118. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/file_io.pyi +0 -0
  119. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/file_pattern_matcher.py +0 -0
  120. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/functions.py +0 -0
  121. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/gpu.py +0 -0
  122. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/image.py +0 -0
  123. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/image.pyi +0 -0
  124. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/io_streams.py +0 -0
  125. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/io_streams.pyi +0 -0
  126. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/mount.py +0 -0
  127. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/mount.pyi +0 -0
  128. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/network_file_system.py +0 -0
  129. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/network_file_system.pyi +0 -0
  130. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/object.py +0 -0
  131. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/object.pyi +0 -0
  132. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/output.py +0 -0
  133. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/parallel_map.py +0 -0
  134. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/parallel_map.pyi +0 -0
  135. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/partial_function.py +0 -0
  136. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/partial_function.pyi +0 -0
  137. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/proxy.py +0 -0
  138. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/proxy.pyi +0 -0
  139. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/py.typed +0 -0
  140. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/queue.py +0 -0
  141. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/queue.pyi +0 -0
  142. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/retries.py +0 -0
  143. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/runner.py +0 -0
  144. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/runner.pyi +0 -0
  145. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/running_app.py +0 -0
  146. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/sandbox.py +0 -0
  147. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/sandbox.pyi +0 -0
  148. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/schedule.py +0 -0
  149. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/scheduler_placement.py +0 -0
  150. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/secret.py +0 -0
  151. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/secret.pyi +0 -0
  152. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/serving.py +0 -0
  153. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/serving.pyi +0 -0
  154. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/snapshot.py +0 -0
  155. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/snapshot.pyi +0 -0
  156. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/stream_type.py +0 -0
  157. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/token_flow.py +0 -0
  158. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/token_flow.pyi +0 -0
  159. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/volume.py +0 -0
  160. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal/volume.pyi +0 -0
  161. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal.egg-info/SOURCES.txt +0 -0
  162. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal.egg-info/dependency_links.txt +0 -0
  163. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal.egg-info/entry_points.txt +0 -0
  164. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal.egg-info/requires.txt +0 -0
  165. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal.egg-info/top_level.txt +0 -0
  166. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal_docs/__init__.py +0 -0
  167. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal_docs/gen_cli_docs.py +0 -0
  168. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal_docs/gen_reference_docs.py +0 -0
  169. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal_docs/mdmd/__init__.py +0 -0
  170. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal_docs/mdmd/mdmd.py +0 -0
  171. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal_docs/mdmd/signatures.py +0 -0
  172. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal_proto/__init__.py +0 -0
  173. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal_proto/api.proto +0 -0
  174. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal_proto/api_grpc.py +0 -0
  175. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal_proto/api_pb2.py +0 -0
  176. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal_proto/api_pb2.pyi +0 -0
  177. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal_proto/api_pb2_grpc.py +0 -0
  178. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal_proto/api_pb2_grpc.pyi +0 -0
  179. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal_proto/modal_api_grpc.py +0 -0
  180. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal_proto/modal_options_grpc.py +0 -0
  181. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal_proto/options.proto +0 -0
  182. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal_proto/options_grpc.py +0 -0
  183. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal_proto/options_pb2.py +0 -0
  184. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal_proto/options_pb2.pyi +0 -0
  185. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal_proto/options_pb2_grpc.py +0 -0
  186. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal_proto/options_pb2_grpc.pyi +0 -0
  187. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal_proto/py.typed +0 -0
  188. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/modal_version/__main__.py +0 -0
  189. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/pyproject.toml +0 -0
  190. {modal-1.1.2.dev37 → modal-1.1.2.dev39}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.1.2.dev37
3
+ Version: 1.1.2.dev39
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License: Apache-2.0
@@ -198,9 +198,12 @@ def call_function(
198
198
  # Send up to this many outputs at a time.
199
199
  current_function_call_id = execution_context.current_function_call_id()
200
200
  assert current_function_call_id is not None # Set above.
201
+ current_attempt_token = execution_context.current_attempt_token()
202
+ assert current_attempt_token is not None # Set above, but can be empty string.
201
203
  generator_queue: asyncio.Queue[Any] = await container_io_manager._queue_create.aio(1024)
202
204
  async with container_io_manager.generator_output_sender(
203
205
  current_function_call_id,
206
+ current_attempt_token,
204
207
  io_context.finalized_function.data_format,
205
208
  generator_queue,
206
209
  ):
@@ -247,9 +250,12 @@ def call_function(
247
250
  # Send up to this many outputs at a time.
248
251
  current_function_call_id = execution_context.current_function_call_id()
249
252
  assert current_function_call_id is not None # Set above.
253
+ current_attempt_token = execution_context.current_attempt_token()
254
+ assert current_attempt_token is not None # Set above, but can be empty string.
250
255
  generator_queue: asyncio.Queue[Any] = container_io_manager._queue_create(1024)
251
256
  with container_io_manager.generator_output_sender(
252
257
  current_function_call_id,
258
+ current_attempt_token,
253
259
  io_context.finalized_function.data_format,
254
260
  generator_queue,
255
261
  ):
@@ -473,7 +473,7 @@ class _InputPlaneInvocation:
473
473
  _stream_function_call_data(
474
474
  self.client,
475
475
  self.stub,
476
- "",
476
+ function_call_id=None,
477
477
  variant="data_out",
478
478
  attempt_token=self.attempt_token,
479
479
  ),
@@ -16,7 +16,7 @@ from modal.config import logger
16
16
  from modal.exception import ExecutionError, InvalidError
17
17
  from modal.experimental import stop_fetching_inputs
18
18
 
19
- from .execution_context import current_function_call_id
19
+ from .execution_context import current_attempt_token, current_function_call_id
20
20
 
21
21
  FIRST_MESSAGE_TIMEOUT_SECONDS = 5.0
22
22
 
@@ -106,6 +106,7 @@ def asgi_app_wrapper(asgi_app, container_io_manager) -> tuple[Callable[..., Asyn
106
106
  raise ExecutionError("Unpexected state in ASGI scope")
107
107
  scope["state"] = state
108
108
  function_call_id = current_function_call_id()
109
+ attempt_token = current_attempt_token()
109
110
  assert function_call_id, "internal error: function_call_id not set in asgi_app() scope"
110
111
 
111
112
  messages_from_app: asyncio.Queue[dict[str, Any]] = asyncio.Queue(1)
@@ -142,7 +143,7 @@ def asgi_app_wrapper(asgi_app, container_io_manager) -> tuple[Callable[..., Asyn
142
143
  # This initial message, "http.request" or "websocket.connect", should be sent
143
144
  # immediately after starting the ASGI app's function call. If it is not received, that
144
145
  # indicates a request cancellation or other abnormal circumstance.
145
- message_gen = container_io_manager.get_data_in.aio(function_call_id)
146
+ message_gen = container_io_manager.get_data_in.aio(function_call_id, attempt_token)
146
147
  first_message_task = asyncio.create_task(message_gen.__anext__())
147
148
 
148
149
  try:
@@ -483,18 +483,21 @@ class _ContainerIOManager:
483
483
  else {"data": data}
484
484
  )
485
485
 
486
- async def get_data_in(self, function_call_id: str) -> AsyncIterator[Any]:
486
+ async def get_data_in(self, function_call_id: str, attempt_token: Optional[str]) -> AsyncIterator[Any]:
487
487
  """Read from the `data_in` stream of a function call."""
488
488
  stub = self._client.stub
489
489
  if self.input_plane_server_url:
490
490
  stub = await self._client.get_stub(self.input_plane_server_url)
491
491
 
492
- async for data in _stream_function_call_data(self._client, stub, function_call_id, "data_in"):
492
+ async for data in _stream_function_call_data(
493
+ self._client, stub, function_call_id, variant="data_in", attempt_token=attempt_token
494
+ ):
493
495
  yield data
494
496
 
495
497
  async def put_data_out(
496
498
  self,
497
499
  function_call_id: str,
500
+ attempt_token: str,
498
501
  start_index: int,
499
502
  data_format: int,
500
503
  serialized_messages: list[Any],
@@ -515,6 +518,8 @@ class _ContainerIOManager:
515
518
  data_chunks.append(chunk)
516
519
 
517
520
  req = api_pb2.FunctionCallPutDataRequest(function_call_id=function_call_id, data_chunks=data_chunks)
521
+ if attempt_token:
522
+ req.attempt_token = attempt_token # oneof clears function_call_id.
518
523
 
519
524
  if self.input_plane_server_url:
520
525
  stub = await self._client.get_stub(self.input_plane_server_url)
@@ -524,7 +529,7 @@ class _ContainerIOManager:
524
529
 
525
530
  @asynccontextmanager
526
531
  async def generator_output_sender(
527
- self, function_call_id: str, data_format: int, message_rx: asyncio.Queue
532
+ self, function_call_id: str, attempt_token: str, data_format: int, message_rx: asyncio.Queue
528
533
  ) -> AsyncGenerator[None, None]:
529
534
  """Runs background task that feeds generator outputs into a function call's `data_out` stream."""
530
535
  GENERATOR_STOP_SENTINEL = Sentinel()
@@ -553,7 +558,7 @@ class _ContainerIOManager:
553
558
  else:
554
559
  serialized_messages.append(serialize_data_format(message, data_format))
555
560
  total_size += len(serialized_messages[-1]) + 512 # 512 bytes for estimated framing overhead
556
- await self.put_data_out(function_call_id, index, data_format, serialized_messages)
561
+ await self.put_data_out(function_call_id, attempt_token, index, data_format, serialized_messages)
557
562
  index += len(serialized_messages)
558
563
 
559
564
  task = asyncio.create_task(generator_output_task())
@@ -135,12 +135,19 @@ class _ContainerIOManager:
135
135
  async def _dynamic_concurrency_loop(self): ...
136
136
  def serialize_data_format(self, obj: typing.Any, data_format: int) -> bytes: ...
137
137
  async def format_blob_data(self, data: bytes) -> dict[str, typing.Any]: ...
138
- def get_data_in(self, function_call_id: str) -> collections.abc.AsyncIterator[typing.Any]:
138
+ def get_data_in(
139
+ self, function_call_id: str, attempt_token: typing.Optional[str]
140
+ ) -> collections.abc.AsyncIterator[typing.Any]:
139
141
  """Read from the `data_in` stream of a function call."""
140
142
  ...
141
143
 
142
144
  async def put_data_out(
143
- self, function_call_id: str, start_index: int, data_format: int, serialized_messages: list[typing.Any]
145
+ self,
146
+ function_call_id: str,
147
+ attempt_token: str,
148
+ start_index: int,
149
+ data_format: int,
150
+ serialized_messages: list[typing.Any],
144
151
  ) -> None:
145
152
  """Put data onto the `data_out` stream of a function call.
146
153
 
@@ -151,7 +158,7 @@ class _ContainerIOManager:
151
158
  ...
152
159
 
153
160
  def generator_output_sender(
154
- self, function_call_id: str, data_format: int, message_rx: asyncio.queues.Queue
161
+ self, function_call_id: str, attempt_token: str, data_format: int, message_rx: asyncio.queues.Queue
155
162
  ) -> typing.AsyncContextManager[None]:
156
163
  """Runs background task that feeds generator outputs into a function call's `data_out` stream."""
157
164
  ...
@@ -334,11 +341,15 @@ class ContainerIOManager:
334
341
  format_blob_data: __format_blob_data_spec[typing_extensions.Self]
335
342
 
336
343
  class __get_data_in_spec(typing_extensions.Protocol[SUPERSELF]):
337
- def __call__(self, /, function_call_id: str) -> typing.Iterator[typing.Any]:
344
+ def __call__(
345
+ self, /, function_call_id: str, attempt_token: typing.Optional[str]
346
+ ) -> typing.Iterator[typing.Any]:
338
347
  """Read from the `data_in` stream of a function call."""
339
348
  ...
340
349
 
341
- def aio(self, /, function_call_id: str) -> collections.abc.AsyncIterator[typing.Any]:
350
+ def aio(
351
+ self, /, function_call_id: str, attempt_token: typing.Optional[str]
352
+ ) -> collections.abc.AsyncIterator[typing.Any]:
342
353
  """Read from the `data_in` stream of a function call."""
343
354
  ...
344
355
 
@@ -346,7 +357,13 @@ class ContainerIOManager:
346
357
 
347
358
  class __put_data_out_spec(typing_extensions.Protocol[SUPERSELF]):
348
359
  def __call__(
349
- self, /, function_call_id: str, start_index: int, data_format: int, serialized_messages: list[typing.Any]
360
+ self,
361
+ /,
362
+ function_call_id: str,
363
+ attempt_token: str,
364
+ start_index: int,
365
+ data_format: int,
366
+ serialized_messages: list[typing.Any],
350
367
  ) -> None:
351
368
  """Put data onto the `data_out` stream of a function call.
352
369
 
@@ -357,7 +374,13 @@ class ContainerIOManager:
357
374
  ...
358
375
 
359
376
  async def aio(
360
- self, /, function_call_id: str, start_index: int, data_format: int, serialized_messages: list[typing.Any]
377
+ self,
378
+ /,
379
+ function_call_id: str,
380
+ attempt_token: str,
381
+ start_index: int,
382
+ data_format: int,
383
+ serialized_messages: list[typing.Any],
361
384
  ) -> None:
362
385
  """Put data onto the `data_out` stream of a function call.
363
386
 
@@ -371,13 +394,13 @@ class ContainerIOManager:
371
394
 
372
395
  class __generator_output_sender_spec(typing_extensions.Protocol[SUPERSELF]):
373
396
  def __call__(
374
- self, /, function_call_id: str, data_format: int, message_rx: asyncio.queues.Queue
397
+ self, /, function_call_id: str, attempt_token: str, data_format: int, message_rx: asyncio.queues.Queue
375
398
  ) -> synchronicity.combined_types.AsyncAndBlockingContextManager[None]:
376
399
  """Runs background task that feeds generator outputs into a function call's `data_out` stream."""
377
400
  ...
378
401
 
379
402
  def aio(
380
- self, /, function_call_id: str, data_format: int, message_rx: asyncio.queues.Queue
403
+ self, /, function_call_id: str, attempt_token: str, data_format: int, message_rx: asyncio.queues.Queue
381
404
  ) -> typing.AsyncContextManager[None]:
382
405
  """Runs background task that feeds generator outputs into a function call's `data_out` stream."""
383
406
  ...
@@ -392,8 +392,8 @@ async def _stream_function_call_data(
392
392
  attempt_token: Optional[str] = None,
393
393
  ) -> AsyncGenerator[Any, None]:
394
394
  """Read from the `data_in` or `data_out` stream of a function call."""
395
- if function_call_id is None and attempt_token is None:
396
- raise ValueError("function_call_id or attempt_token is required for data_out stream")
395
+ if not function_call_id and not attempt_token:
396
+ raise ValueError("function_call_id or attempt_token is required to read from a data stream")
397
397
 
398
398
  if stub is None:
399
399
  stub = client.stub
@@ -415,8 +415,9 @@ async def _stream_function_call_data(
415
415
  req = api_pb2.FunctionCallGetDataRequest(
416
416
  function_call_id=function_call_id,
417
417
  last_index=last_index,
418
- attempt_token=attempt_token,
419
418
  )
419
+ if attempt_token:
420
+ req.attempt_token = attempt_token # oneof clears function_call_id.
420
421
  try:
421
422
  async for chunk in stub_fn.unary_stream(req):
422
423
  if chunk.index <= last_index:
@@ -33,7 +33,7 @@ class _Client:
33
33
  server_url: str,
34
34
  client_type: int,
35
35
  credentials: typing.Optional[tuple[str, str]],
36
- version: str = "1.1.2.dev37",
36
+ version: str = "1.1.2.dev39",
37
37
  ):
38
38
  """mdmd:hidden
39
39
  The Modal client object is not intended to be instantiated directly by users.
@@ -164,7 +164,7 @@ class Client:
164
164
  server_url: str,
165
165
  client_type: int,
166
166
  credentials: typing.Optional[tuple[str, str]],
167
- version: str = "1.1.2.dev37",
167
+ version: str = "1.1.2.dev39",
168
168
  ):
169
169
  """mdmd:hidden
170
170
  The Modal client object is not intended to be instantiated directly by users.
@@ -433,7 +433,7 @@ class Function(
433
433
 
434
434
  _call_generator: ___call_generator_spec[typing_extensions.Self]
435
435
 
436
- class __remote_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER, SUPERSELF]):
436
+ class __remote_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER, SUPERSELF]):
437
437
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> ReturnType_INNER:
438
438
  """Calls the function remotely, executing it with the given arguments and returning the execution's result."""
439
439
  ...
@@ -442,7 +442,7 @@ class Function(
442
442
  """Calls the function remotely, executing it with the given arguments and returning the execution's result."""
443
443
  ...
444
444
 
445
- remote: __remote_spec[modal._functions.ReturnType, modal._functions.P, typing_extensions.Self]
445
+ remote: __remote_spec[modal._functions.P, modal._functions.ReturnType, typing_extensions.Self]
446
446
 
447
447
  class __remote_gen_spec(typing_extensions.Protocol[SUPERSELF]):
448
448
  def __call__(self, /, *args, **kwargs) -> typing.Generator[typing.Any, None, None]:
@@ -469,7 +469,7 @@ class Function(
469
469
  """
470
470
  ...
471
471
 
472
- class ___experimental_spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER, SUPERSELF]):
472
+ class ___experimental_spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER, SUPERSELF]):
473
473
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
474
474
  """[Experimental] Calls the function with the given arguments, without waiting for the results.
475
475
 
@@ -493,7 +493,7 @@ class Function(
493
493
  ...
494
494
 
495
495
  _experimental_spawn: ___experimental_spawn_spec[
496
- modal._functions.ReturnType, modal._functions.P, typing_extensions.Self
496
+ modal._functions.P, modal._functions.ReturnType, typing_extensions.Self
497
497
  ]
498
498
 
499
499
  class ___spawn_map_inner_spec(typing_extensions.Protocol[P_INNER, SUPERSELF]):
@@ -502,7 +502,7 @@ class Function(
502
502
 
503
503
  _spawn_map_inner: ___spawn_map_inner_spec[modal._functions.P, typing_extensions.Self]
504
504
 
505
- class __spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER, SUPERSELF]):
505
+ class __spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER, SUPERSELF]):
506
506
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
507
507
  """Calls the function with the given arguments, without waiting for the results.
508
508
 
@@ -523,7 +523,7 @@ class Function(
523
523
  """
524
524
  ...
525
525
 
526
- spawn: __spawn_spec[modal._functions.ReturnType, modal._functions.P, typing_extensions.Self]
526
+ spawn: __spawn_spec[modal._functions.P, modal._functions.ReturnType, typing_extensions.Self]
527
527
 
528
528
  def get_raw_f(self) -> collections.abc.Callable[..., typing.Any]:
529
529
  """Return the inner Python object wrapped by this Modal Function."""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.1.2.dev37
3
+ Version: 1.1.2.dev39
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.1.2.dev37"
4
+ __version__ = "1.1.2.dev39"
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