modAL 1.1.2__tar.gz → 1.1.2.dev0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (193) hide show
  1. {modal-1.1.2 → modal-1.1.2.dev0}/PKG-INFO +2 -2
  2. {modal-1.1.2 → modal-1.1.2.dev0}/modal/__main__.py +2 -1
  3. {modal-1.1.2 → modal-1.1.2.dev0}/modal/_container_entrypoint.py +7 -18
  4. {modal-1.1.2 → modal-1.1.2.dev0}/modal/_functions.py +13 -135
  5. {modal-1.1.2 → modal-1.1.2.dev0}/modal/_object.py +2 -13
  6. {modal-1.1.2 → modal-1.1.2.dev0}/modal/_partial_function.py +8 -8
  7. {modal-1.1.2 → modal-1.1.2.dev0}/modal/_runtime/asgi.py +2 -3
  8. {modal-1.1.2 → modal-1.1.2.dev0}/modal/_runtime/container_io_manager.py +14 -20
  9. {modal-1.1.2 → modal-1.1.2.dev0}/modal/_runtime/container_io_manager.pyi +13 -38
  10. {modal-1.1.2 → modal-1.1.2.dev0}/modal/_runtime/execution_context.py +2 -18
  11. {modal-1.1.2 → modal-1.1.2.dev0}/modal/_runtime/execution_context.pyi +1 -4
  12. {modal-1.1.2 → modal-1.1.2.dev0}/modal/_utils/blob_utils.py +24 -83
  13. {modal-1.1.2 → modal-1.1.2.dev0}/modal/_utils/function_utils.py +3 -4
  14. modal-1.1.2.dev0/modal/_utils/time_utils.py +19 -0
  15. {modal-1.1.2 → modal-1.1.2.dev0}/modal/app.py +4 -8
  16. {modal-1.1.2 → modal-1.1.2.dev0}/modal/app.pyi +8 -8
  17. {modal-1.1.2 → modal-1.1.2.dev0}/modal/cli/dict.py +11 -14
  18. {modal-1.1.2 → modal-1.1.2.dev0}/modal/cli/entry_point.py +3 -9
  19. modal-1.1.2.dev0/modal/cli/launch.py +97 -0
  20. {modal-1.1.2 → modal-1.1.2.dev0}/modal/cli/profile.py +0 -1
  21. {modal-1.1.2 → modal-1.1.2.dev0}/modal/cli/queues.py +19 -49
  22. {modal-1.1.2 → modal-1.1.2.dev0}/modal/cli/secret.py +18 -45
  23. {modal-1.1.2 → modal-1.1.2.dev0}/modal/cli/volume.py +16 -14
  24. {modal-1.1.2 → modal-1.1.2.dev0}/modal/client.pyi +10 -2
  25. {modal-1.1.2 → modal-1.1.2.dev0}/modal/cls.py +2 -12
  26. {modal-1.1.2 → modal-1.1.2.dev0}/modal/cls.pyi +1 -9
  27. {modal-1.1.2 → modal-1.1.2.dev0}/modal/config.py +7 -7
  28. {modal-1.1.2 → modal-1.1.2.dev0}/modal/dict.py +12 -206
  29. {modal-1.1.2 → modal-1.1.2.dev0}/modal/dict.pyi +4 -358
  30. {modal-1.1.2 → modal-1.1.2.dev0}/modal/experimental/__init__.py +0 -130
  31. {modal-1.1.2 → modal-1.1.2.dev0}/modal/file_io.py +1 -1
  32. {modal-1.1.2 → modal-1.1.2.dev0}/modal/file_io.pyi +2 -2
  33. {modal-1.1.2 → modal-1.1.2.dev0}/modal/file_pattern_matcher.py +16 -25
  34. {modal-1.1.2 → modal-1.1.2.dev0}/modal/functions.pyi +5 -105
  35. {modal-1.1.2 → modal-1.1.2.dev0}/modal/image.py +1 -1
  36. {modal-1.1.2 → modal-1.1.2.dev0}/modal/image.pyi +7 -7
  37. {modal-1.1.2 → modal-1.1.2.dev0}/modal/mount.py +13 -20
  38. {modal-1.1.2 → modal-1.1.2.dev0}/modal/mount.pyi +3 -16
  39. {modal-1.1.2 → modal-1.1.2.dev0}/modal/network_file_system.py +2 -8
  40. {modal-1.1.2 → modal-1.1.2.dev0}/modal/object.pyi +0 -3
  41. {modal-1.1.2 → modal-1.1.2.dev0}/modal/parallel_map.py +101 -346
  42. {modal-1.1.2 → modal-1.1.2.dev0}/modal/parallel_map.pyi +0 -108
  43. {modal-1.1.2 → modal-1.1.2.dev0}/modal/proxy.py +1 -2
  44. {modal-1.1.2 → modal-1.1.2.dev0}/modal/queue.py +9 -199
  45. {modal-1.1.2 → modal-1.1.2.dev0}/modal/queue.pyi +3 -357
  46. {modal-1.1.2 → modal-1.1.2.dev0}/modal/sandbox.py +5 -6
  47. {modal-1.1.2 → modal-1.1.2.dev0}/modal/sandbox.pyi +14 -17
  48. {modal-1.1.2 → modal-1.1.2.dev0}/modal/secret.py +3 -196
  49. modal-1.1.2.dev0/modal/secret.pyi +297 -0
  50. {modal-1.1.2 → modal-1.1.2.dev0}/modal/volume.py +22 -238
  51. {modal-1.1.2 → modal-1.1.2.dev0}/modal/volume.pyi +7 -402
  52. {modal-1.1.2 → modal-1.1.2.dev0}/modal.egg-info/PKG-INFO +2 -2
  53. {modal-1.1.2 → modal-1.1.2.dev0}/modal.egg-info/SOURCES.txt +0 -2
  54. {modal-1.1.2 → modal-1.1.2.dev0}/modal.egg-info/requires.txt +1 -1
  55. {modal-1.1.2 → modal-1.1.2.dev0}/modal_docs/mdmd/mdmd.py +1 -11
  56. {modal-1.1.2 → modal-1.1.2.dev0}/modal_proto/api.proto +10 -36
  57. {modal-1.1.2 → modal-1.1.2.dev0}/modal_proto/api_grpc.py +0 -32
  58. {modal-1.1.2 → modal-1.1.2.dev0}/modal_proto/api_pb2.py +597 -627
  59. {modal-1.1.2 → modal-1.1.2.dev0}/modal_proto/api_pb2.pyi +17 -101
  60. {modal-1.1.2 → modal-1.1.2.dev0}/modal_proto/api_pb2_grpc.py +2 -67
  61. {modal-1.1.2 → modal-1.1.2.dev0}/modal_proto/api_pb2_grpc.pyi +8 -24
  62. {modal-1.1.2 → modal-1.1.2.dev0}/modal_proto/modal_api_grpc.py +0 -2
  63. {modal-1.1.2 → modal-1.1.2.dev0}/modal_version/__init__.py +1 -1
  64. {modal-1.1.2 → modal-1.1.2.dev0}/pyproject.toml +1 -1
  65. modal-1.1.2/modal/_utils/time_utils.py +0 -43
  66. modal-1.1.2/modal/cli/launch.py +0 -195
  67. modal-1.1.2/modal/cli/programs/launch_instance_ssh.py +0 -94
  68. modal-1.1.2/modal/cli/programs/run_marimo.py +0 -95
  69. modal-1.1.2/modal/secret.pyi +0 -669
  70. {modal-1.1.2 → modal-1.1.2.dev0}/LICENSE +0 -0
  71. {modal-1.1.2 → modal-1.1.2.dev0}/README.md +0 -0
  72. {modal-1.1.2 → modal-1.1.2.dev0}/modal/__init__.py +0 -0
  73. {modal-1.1.2 → modal-1.1.2.dev0}/modal/_clustered_functions.py +0 -0
  74. {modal-1.1.2 → modal-1.1.2.dev0}/modal/_clustered_functions.pyi +0 -0
  75. {modal-1.1.2 → modal-1.1.2.dev0}/modal/_ipython.py +0 -0
  76. {modal-1.1.2 → modal-1.1.2.dev0}/modal/_location.py +0 -0
  77. {modal-1.1.2 → modal-1.1.2.dev0}/modal/_output.py +0 -0
  78. {modal-1.1.2 → modal-1.1.2.dev0}/modal/_pty.py +0 -0
  79. {modal-1.1.2 → modal-1.1.2.dev0}/modal/_resolver.py +0 -0
  80. {modal-1.1.2 → modal-1.1.2.dev0}/modal/_resources.py +0 -0
  81. {modal-1.1.2 → modal-1.1.2.dev0}/modal/_runtime/__init__.py +0 -0
  82. {modal-1.1.2 → modal-1.1.2.dev0}/modal/_runtime/gpu_memory_snapshot.py +0 -0
  83. {modal-1.1.2 → modal-1.1.2.dev0}/modal/_runtime/telemetry.py +0 -0
  84. {modal-1.1.2 → modal-1.1.2.dev0}/modal/_runtime/user_code_imports.py +0 -0
  85. {modal-1.1.2 → modal-1.1.2.dev0}/modal/_serialization.py +0 -0
  86. {modal-1.1.2 → modal-1.1.2.dev0}/modal/_traceback.py +0 -0
  87. {modal-1.1.2 → modal-1.1.2.dev0}/modal/_tunnel.py +0 -0
  88. {modal-1.1.2 → modal-1.1.2.dev0}/modal/_tunnel.pyi +0 -0
  89. {modal-1.1.2 → modal-1.1.2.dev0}/modal/_type_manager.py +0 -0
  90. {modal-1.1.2 → modal-1.1.2.dev0}/modal/_utils/__init__.py +0 -0
  91. {modal-1.1.2 → modal-1.1.2.dev0}/modal/_utils/app_utils.py +0 -0
  92. {modal-1.1.2 → modal-1.1.2.dev0}/modal/_utils/async_utils.py +0 -0
  93. {modal-1.1.2 → modal-1.1.2.dev0}/modal/_utils/auth_token_manager.py +0 -0
  94. {modal-1.1.2 → modal-1.1.2.dev0}/modal/_utils/bytes_io_segment_payload.py +0 -0
  95. {modal-1.1.2 → modal-1.1.2.dev0}/modal/_utils/deprecation.py +0 -0
  96. {modal-1.1.2 → modal-1.1.2.dev0}/modal/_utils/docker_utils.py +0 -0
  97. {modal-1.1.2 → modal-1.1.2.dev0}/modal/_utils/git_utils.py +0 -0
  98. {modal-1.1.2 → modal-1.1.2.dev0}/modal/_utils/grpc_testing.py +0 -0
  99. {modal-1.1.2 → modal-1.1.2.dev0}/modal/_utils/grpc_utils.py +0 -0
  100. {modal-1.1.2 → modal-1.1.2.dev0}/modal/_utils/hash_utils.py +0 -0
  101. {modal-1.1.2 → modal-1.1.2.dev0}/modal/_utils/http_utils.py +0 -0
  102. {modal-1.1.2 → modal-1.1.2.dev0}/modal/_utils/jwt_utils.py +0 -0
  103. {modal-1.1.2 → modal-1.1.2.dev0}/modal/_utils/logger.py +0 -0
  104. {modal-1.1.2 → modal-1.1.2.dev0}/modal/_utils/mount_utils.py +0 -0
  105. {modal-1.1.2 → modal-1.1.2.dev0}/modal/_utils/name_utils.py +0 -0
  106. {modal-1.1.2 → modal-1.1.2.dev0}/modal/_utils/package_utils.py +0 -0
  107. {modal-1.1.2 → modal-1.1.2.dev0}/modal/_utils/pattern_utils.py +0 -0
  108. {modal-1.1.2 → modal-1.1.2.dev0}/modal/_utils/rand_pb_testing.py +0 -0
  109. {modal-1.1.2 → modal-1.1.2.dev0}/modal/_utils/shell_utils.py +0 -0
  110. {modal-1.1.2 → modal-1.1.2.dev0}/modal/_vendor/__init__.py +0 -0
  111. {modal-1.1.2 → modal-1.1.2.dev0}/modal/_vendor/a2wsgi_wsgi.py +0 -0
  112. {modal-1.1.2 → modal-1.1.2.dev0}/modal/_vendor/cloudpickle.py +0 -0
  113. {modal-1.1.2 → modal-1.1.2.dev0}/modal/_vendor/tblib.py +0 -0
  114. {modal-1.1.2 → modal-1.1.2.dev0}/modal/_watcher.py +0 -0
  115. {modal-1.1.2 → modal-1.1.2.dev0}/modal/builder/2023.12.312.txt +0 -0
  116. {modal-1.1.2 → modal-1.1.2.dev0}/modal/builder/2023.12.txt +0 -0
  117. {modal-1.1.2 → modal-1.1.2.dev0}/modal/builder/2024.04.txt +0 -0
  118. {modal-1.1.2 → modal-1.1.2.dev0}/modal/builder/2024.10.txt +0 -0
  119. {modal-1.1.2 → modal-1.1.2.dev0}/modal/builder/2025.06.txt +0 -0
  120. {modal-1.1.2 → modal-1.1.2.dev0}/modal/builder/PREVIEW.txt +0 -0
  121. {modal-1.1.2 → modal-1.1.2.dev0}/modal/builder/README.md +0 -0
  122. {modal-1.1.2 → modal-1.1.2.dev0}/modal/builder/base-images.json +0 -0
  123. {modal-1.1.2 → modal-1.1.2.dev0}/modal/call_graph.py +0 -0
  124. {modal-1.1.2 → modal-1.1.2.dev0}/modal/cli/__init__.py +0 -0
  125. {modal-1.1.2 → modal-1.1.2.dev0}/modal/cli/_download.py +0 -0
  126. {modal-1.1.2 → modal-1.1.2.dev0}/modal/cli/_traceback.py +0 -0
  127. {modal-1.1.2 → modal-1.1.2.dev0}/modal/cli/app.py +0 -0
  128. {modal-1.1.2 → modal-1.1.2.dev0}/modal/cli/cluster.py +0 -0
  129. {modal-1.1.2 → modal-1.1.2.dev0}/modal/cli/config.py +0 -0
  130. {modal-1.1.2 → modal-1.1.2.dev0}/modal/cli/container.py +0 -0
  131. {modal-1.1.2 → modal-1.1.2.dev0}/modal/cli/environment.py +0 -0
  132. {modal-1.1.2 → modal-1.1.2.dev0}/modal/cli/import_refs.py +0 -0
  133. {modal-1.1.2 → modal-1.1.2.dev0}/modal/cli/network_file_system.py +0 -0
  134. {modal-1.1.2 → modal-1.1.2.dev0}/modal/cli/programs/__init__.py +0 -0
  135. {modal-1.1.2 → modal-1.1.2.dev0}/modal/cli/programs/run_jupyter.py +0 -0
  136. {modal-1.1.2 → modal-1.1.2.dev0}/modal/cli/programs/vscode.py +0 -0
  137. {modal-1.1.2 → modal-1.1.2.dev0}/modal/cli/run.py +0 -0
  138. {modal-1.1.2 → modal-1.1.2.dev0}/modal/cli/token.py +0 -0
  139. {modal-1.1.2 → modal-1.1.2.dev0}/modal/cli/utils.py +0 -0
  140. {modal-1.1.2 → modal-1.1.2.dev0}/modal/client.py +0 -0
  141. {modal-1.1.2 → modal-1.1.2.dev0}/modal/cloud_bucket_mount.py +0 -0
  142. {modal-1.1.2 → modal-1.1.2.dev0}/modal/cloud_bucket_mount.pyi +0 -0
  143. {modal-1.1.2 → modal-1.1.2.dev0}/modal/container_process.py +0 -0
  144. {modal-1.1.2 → modal-1.1.2.dev0}/modal/container_process.pyi +0 -0
  145. {modal-1.1.2 → modal-1.1.2.dev0}/modal/environments.py +0 -0
  146. {modal-1.1.2 → modal-1.1.2.dev0}/modal/environments.pyi +0 -0
  147. {modal-1.1.2 → modal-1.1.2.dev0}/modal/exception.py +0 -0
  148. {modal-1.1.2 → modal-1.1.2.dev0}/modal/experimental/flash.py +0 -0
  149. {modal-1.1.2 → modal-1.1.2.dev0}/modal/experimental/flash.pyi +0 -0
  150. {modal-1.1.2 → modal-1.1.2.dev0}/modal/experimental/ipython.py +0 -0
  151. {modal-1.1.2 → modal-1.1.2.dev0}/modal/functions.py +0 -0
  152. {modal-1.1.2 → modal-1.1.2.dev0}/modal/gpu.py +0 -0
  153. {modal-1.1.2 → modal-1.1.2.dev0}/modal/io_streams.py +0 -0
  154. {modal-1.1.2 → modal-1.1.2.dev0}/modal/io_streams.pyi +0 -0
  155. {modal-1.1.2 → modal-1.1.2.dev0}/modal/network_file_system.pyi +0 -0
  156. {modal-1.1.2 → modal-1.1.2.dev0}/modal/object.py +0 -0
  157. {modal-1.1.2 → modal-1.1.2.dev0}/modal/output.py +0 -0
  158. {modal-1.1.2 → modal-1.1.2.dev0}/modal/partial_function.py +0 -0
  159. {modal-1.1.2 → modal-1.1.2.dev0}/modal/partial_function.pyi +0 -0
  160. {modal-1.1.2 → modal-1.1.2.dev0}/modal/proxy.pyi +0 -0
  161. {modal-1.1.2 → modal-1.1.2.dev0}/modal/py.typed +0 -0
  162. {modal-1.1.2 → modal-1.1.2.dev0}/modal/retries.py +0 -0
  163. {modal-1.1.2 → modal-1.1.2.dev0}/modal/runner.py +0 -0
  164. {modal-1.1.2 → modal-1.1.2.dev0}/modal/runner.pyi +0 -0
  165. {modal-1.1.2 → modal-1.1.2.dev0}/modal/running_app.py +0 -0
  166. {modal-1.1.2 → modal-1.1.2.dev0}/modal/schedule.py +0 -0
  167. {modal-1.1.2 → modal-1.1.2.dev0}/modal/scheduler_placement.py +0 -0
  168. {modal-1.1.2 → modal-1.1.2.dev0}/modal/serving.py +0 -0
  169. {modal-1.1.2 → modal-1.1.2.dev0}/modal/serving.pyi +0 -0
  170. {modal-1.1.2 → modal-1.1.2.dev0}/modal/snapshot.py +0 -0
  171. {modal-1.1.2 → modal-1.1.2.dev0}/modal/snapshot.pyi +0 -0
  172. {modal-1.1.2 → modal-1.1.2.dev0}/modal/stream_type.py +0 -0
  173. {modal-1.1.2 → modal-1.1.2.dev0}/modal/token_flow.py +0 -0
  174. {modal-1.1.2 → modal-1.1.2.dev0}/modal/token_flow.pyi +0 -0
  175. {modal-1.1.2 → modal-1.1.2.dev0}/modal.egg-info/dependency_links.txt +0 -0
  176. {modal-1.1.2 → modal-1.1.2.dev0}/modal.egg-info/entry_points.txt +0 -0
  177. {modal-1.1.2 → modal-1.1.2.dev0}/modal.egg-info/top_level.txt +0 -0
  178. {modal-1.1.2 → modal-1.1.2.dev0}/modal_docs/__init__.py +0 -0
  179. {modal-1.1.2 → modal-1.1.2.dev0}/modal_docs/gen_cli_docs.py +0 -0
  180. {modal-1.1.2 → modal-1.1.2.dev0}/modal_docs/gen_reference_docs.py +0 -0
  181. {modal-1.1.2 → modal-1.1.2.dev0}/modal_docs/mdmd/__init__.py +0 -0
  182. {modal-1.1.2 → modal-1.1.2.dev0}/modal_docs/mdmd/signatures.py +0 -0
  183. {modal-1.1.2 → modal-1.1.2.dev0}/modal_proto/__init__.py +0 -0
  184. {modal-1.1.2 → modal-1.1.2.dev0}/modal_proto/modal_options_grpc.py +0 -0
  185. {modal-1.1.2 → modal-1.1.2.dev0}/modal_proto/options.proto +0 -0
  186. {modal-1.1.2 → modal-1.1.2.dev0}/modal_proto/options_grpc.py +0 -0
  187. {modal-1.1.2 → modal-1.1.2.dev0}/modal_proto/options_pb2.py +0 -0
  188. {modal-1.1.2 → modal-1.1.2.dev0}/modal_proto/options_pb2.pyi +0 -0
  189. {modal-1.1.2 → modal-1.1.2.dev0}/modal_proto/options_pb2_grpc.py +0 -0
  190. {modal-1.1.2 → modal-1.1.2.dev0}/modal_proto/options_pb2_grpc.pyi +0 -0
  191. {modal-1.1.2 → modal-1.1.2.dev0}/modal_proto/py.typed +0 -0
  192. {modal-1.1.2 → modal-1.1.2.dev0}/modal_version/__main__.py +0 -0
  193. {modal-1.1.2 → modal-1.1.2.dev0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.1.2
3
+ Version: 1.1.2.dev0
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License: Apache-2.0
@@ -22,7 +22,7 @@ Requires-Dist: click~=8.1
22
22
  Requires-Dist: grpclib<0.4.9,>=0.4.7
23
23
  Requires-Dist: protobuf!=4.24.0,<7.0,>=3.19
24
24
  Requires-Dist: rich>=12.0.0
25
- Requires-Dist: synchronicity~=0.10.2
25
+ Requires-Dist: synchronicity~=0.10.1
26
26
  Requires-Dist: toml
27
27
  Requires-Dist: typer>=0.9
28
28
  Requires-Dist: types-certifi
@@ -37,6 +37,7 @@ def main():
37
37
 
38
38
  from grpclib import GRPCError, Status
39
39
  from rich.panel import Panel
40
+ from rich.text import Text
40
41
 
41
42
  if isinstance(exc, GRPCError):
42
43
  status_map = {
@@ -68,7 +69,7 @@ def main():
68
69
  content = f"{content}\n\nNote: {' '.join(notes)}"
69
70
 
70
71
  console = make_console(stderr=True)
71
- panel = Panel(content, title=title, title_align="left", border_style="red")
72
+ panel = Panel(Text(content), title=title, title_align="left", border_style="red")
72
73
  console.print(panel, highlight=False)
73
74
  sys.exit(1)
74
75
 
@@ -185,9 +185,8 @@ def call_function(
185
185
  ):
186
186
  async def run_input_async(io_context: IOContext) -> None:
187
187
  started_at = time.time()
188
- reset_context = execution_context._set_current_context_ids(
189
- io_context.input_ids, io_context.function_call_ids, io_context.attempt_tokens
190
- )
188
+ input_ids, function_call_ids = io_context.input_ids, io_context.function_call_ids
189
+ reset_context = execution_context._set_current_context_ids(input_ids, function_call_ids)
191
190
  async with container_io_manager.handle_input_exception.aio(io_context, started_at):
192
191
  res = io_context.call_finalized_function()
193
192
  # TODO(erikbern): any exception below shouldn't be considered a user exception
@@ -196,14 +195,9 @@ def call_function(
196
195
  raise InvalidError(f"Async generator function returned value of type {type(res)}")
197
196
 
198
197
  # Send up to this many outputs at a time.
199
- current_function_call_id = execution_context.current_function_call_id()
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.
203
198
  generator_queue: asyncio.Queue[Any] = await container_io_manager._queue_create.aio(1024)
204
199
  async with container_io_manager.generator_output_sender(
205
- current_function_call_id,
206
- current_attempt_token,
200
+ function_call_ids[0],
207
201
  io_context.finalized_function.data_format,
208
202
  generator_queue,
209
203
  ):
@@ -236,9 +230,8 @@ def call_function(
236
230
 
237
231
  def run_input_sync(io_context: IOContext) -> None:
238
232
  started_at = time.time()
239
- reset_context = execution_context._set_current_context_ids(
240
- io_context.input_ids, io_context.function_call_ids, io_context.attempt_tokens
241
- )
233
+ input_ids, function_call_ids = io_context.input_ids, io_context.function_call_ids
234
+ reset_context = execution_context._set_current_context_ids(input_ids, function_call_ids)
242
235
  with container_io_manager.handle_input_exception(io_context, started_at):
243
236
  res = io_context.call_finalized_function()
244
237
 
@@ -248,14 +241,10 @@ def call_function(
248
241
  raise InvalidError(f"Generator function returned value of type {type(res)}")
249
242
 
250
243
  # Send up to this many outputs at a time.
251
- current_function_call_id = execution_context.current_function_call_id()
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.
255
244
  generator_queue: asyncio.Queue[Any] = container_io_manager._queue_create(1024)
245
+
256
246
  with container_io_manager.generator_output_sender(
257
- current_function_call_id,
258
- current_attempt_token,
247
+ function_call_ids[0],
259
248
  io_context.finalized_function.data_format,
260
249
  generator_queue,
261
250
  ):
@@ -9,7 +9,7 @@ import warnings
9
9
  from collections.abc import AsyncGenerator, Sequence, Sized
10
10
  from dataclasses import dataclass
11
11
  from pathlib import PurePosixPath
12
- from typing import TYPE_CHECKING, Any, AsyncIterator, Callable, Optional, Union
12
+ from typing import TYPE_CHECKING, Any, Callable, Optional, Union
13
13
 
14
14
  import typing_extensions
15
15
  from google.protobuf.message import Message
@@ -71,8 +71,6 @@ from .mount import _get_client_mount, _Mount
71
71
  from .network_file_system import _NetworkFileSystem, network_file_system_mount_protos
72
72
  from .output import _get_output_manager
73
73
  from .parallel_map import (
74
- _experimental_spawn_map_async,
75
- _experimental_spawn_map_sync,
76
74
  _for_each_async,
77
75
  _for_each_sync,
78
76
  _map_async,
@@ -80,7 +78,6 @@ from .parallel_map import (
80
78
  _map_invocation_inputplane,
81
79
  _map_sync,
82
80
  _spawn_map_async,
83
- _spawn_map_invocation,
84
81
  _spawn_map_sync,
85
82
  _starmap_async,
86
83
  _starmap_sync,
@@ -217,11 +214,7 @@ class _Invocation:
217
214
  return _Invocation(stub, function_call_id, client, retry_context)
218
215
 
219
216
  async def pop_function_call_outputs(
220
- self,
221
- index: int = 0,
222
- timeout: Optional[float] = None,
223
- clear_on_success: bool = False,
224
- input_jwts: Optional[list[str]] = None,
217
+ self, timeout: Optional[float], clear_on_success: bool, input_jwts: Optional[list[str]] = None
225
218
  ) -> api_pb2.FunctionGetOutputsResponse:
226
219
  t0 = time.time()
227
220
  if timeout is None:
@@ -239,8 +232,6 @@ class _Invocation:
239
232
  clear_on_success=clear_on_success,
240
233
  requested_at=time.time(),
241
234
  input_jwts=input_jwts,
242
- start_idx=index,
243
- end_idx=index,
244
235
  )
245
236
  response: api_pb2.FunctionGetOutputsResponse = await retry_transient_errors(
246
237
  self.stub.FunctionGetOutputs,
@@ -274,7 +265,6 @@ class _Invocation:
274
265
  # waits indefinitely for a single result for the function, and clear the outputs buffer after
275
266
  item: api_pb2.FunctionGetOutputsItem = (
276
267
  await self.pop_function_call_outputs(
277
- index=0,
278
268
  timeout=None,
279
269
  clear_on_success=True,
280
270
  input_jwts=[expected_jwt] if expected_jwt else None,
@@ -318,16 +308,14 @@ class _Invocation:
318
308
 
319
309
  await self._retry_input()
320
310
 
321
- async def poll_function(self, timeout: Optional[float] = None, *, index: int = 0):
311
+ async def poll_function(self, timeout: Optional[float] = None):
322
312
  """Waits up to timeout for a result from a function.
323
313
 
324
314
  If timeout is `None`, waits indefinitely. This function is not
325
315
  cancellation-safe.
326
316
  """
327
317
  response: api_pb2.FunctionGetOutputsResponse = await self.pop_function_call_outputs(
328
- index=index,
329
- timeout=timeout,
330
- clear_on_success=False,
318
+ timeout=timeout, clear_on_success=False
331
319
  )
332
320
  if len(response.outputs) == 0 and response.num_unfinished_inputs == 0:
333
321
  # if no unfinished inputs and no outputs, then function expired
@@ -360,47 +348,11 @@ class _Invocation:
360
348
  if items_total is not None and items_received >= items_total:
361
349
  break
362
350
 
363
- async def enumerate(self, start_index: int, end_index: int):
364
- """Iterate over the results of the function call in the range [start_index, end_index)."""
365
- limit = 49
366
- current_index = start_index
367
- while current_index < end_index:
368
- # batch_end_indx is inclusive, so we subtract 1 to get the last index in the batch.
369
- batch_end_index = min(current_index + limit, end_index) - 1
370
- request = api_pb2.FunctionGetOutputsRequest(
371
- function_call_id=self.function_call_id,
372
- timeout=0,
373
- last_entry_id="0-0",
374
- clear_on_success=False,
375
- requested_at=time.time(),
376
- start_idx=current_index,
377
- end_idx=batch_end_index,
378
- )
379
- response: api_pb2.FunctionGetOutputsResponse = await retry_transient_errors(
380
- self.stub.FunctionGetOutputs,
381
- request,
382
- attempt_timeout=ATTEMPT_TIMEOUT_GRACE_PERIOD,
383
- )
384
-
385
- outputs = list(response.outputs)
386
- outputs.sort(key=lambda x: x.idx)
387
- for output in outputs:
388
- if output.idx != current_index:
389
- break
390
- result = await _process_result(output.result, output.data_format, self.stub, self.client)
391
- yield output.idx, result
392
- current_index += 1
393
-
394
- # We're missing current_index, so we need to poll the function for the next result
395
- if len(outputs) < (batch_end_index - current_index + 1):
396
- result = await self.poll_function(index=current_index)
397
- yield current_index, result
398
- current_index += 1
399
-
400
351
 
401
352
  class _InputPlaneInvocation:
402
353
  """Internal client representation of a single-input call to a Modal Function using the input
403
- plane server API."""
354
+ plane server API. As of 4/22/2025, this class is experimental and not used in production.
355
+ It is OK to make breaking changes to this class."""
404
356
 
405
357
  stub: ModalClientModal
406
358
 
@@ -510,7 +462,7 @@ class _InputPlaneInvocation:
510
462
  _stream_function_call_data(
511
463
  self.client,
512
464
  self.stub,
513
- function_call_id=None,
465
+ "",
514
466
  variant="data_out",
515
467
  attempt_token=self.attempt_token,
516
468
  ),
@@ -651,7 +603,7 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
651
603
  memory: Optional[Union[int, tuple[int, int]]] = None,
652
604
  proxy: Optional[_Proxy] = None,
653
605
  retries: Optional[Union[int, Retries]] = None,
654
- timeout: int = 300,
606
+ timeout: Optional[int] = None,
655
607
  min_containers: Optional[int] = None,
656
608
  max_containers: Optional[int] = None,
657
609
  buffer_containers: Optional[int] = None,
@@ -1178,8 +1130,6 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
1178
1130
  target_concurrent_inputs=options.target_concurrent_inputs,
1179
1131
  batch_max_size=options.batch_max_size,
1180
1132
  batch_linger_ms=options.batch_wait_ms,
1181
- scheduler_placement=options.scheduler_placement,
1182
- cloud_provider_str=options.cloud,
1183
1133
  )
1184
1134
  else:
1185
1135
  options_pb = None
@@ -1324,8 +1274,7 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
1324
1274
 
1325
1275
  self._hydrate(response.function_id, resolver.client, response.handle_metadata)
1326
1276
 
1327
- environment_rep = f", environment_name={environment_name!r}" if environment_name else ""
1328
- rep = f"modal.Function.from_name('{app_name}', '{name}'{environment_rep})"
1277
+ rep = f"Function.from_name('{app_name}', '{name}')"
1329
1278
  return cls._from_loader(_load_remote, rep, is_another_app=True, hydrate_lazily=True)
1330
1279
 
1331
1280
  @classmethod
@@ -1594,22 +1543,6 @@ Use the `Function.get_web_url()` method instead.
1594
1543
  async for item in stream:
1595
1544
  yield item
1596
1545
 
1597
- @live_method
1598
- async def _spawn_map(self, input_queue: _SynchronizedQueue) -> "_FunctionCall[ReturnType]":
1599
- self._check_no_web_url("spawn_map")
1600
- if self._is_generator:
1601
- raise InvalidError("A generator function cannot be called with `.spawn_map(...)`.")
1602
-
1603
- assert self._function_name
1604
- function_call_id, num_inputs = await _spawn_map_invocation(
1605
- self,
1606
- input_queue,
1607
- self.client,
1608
- )
1609
- metadata = api_pb2.FunctionCallFromIdResponse(function_call_id=function_call_id, num_inputs=num_inputs)
1610
- fc: _FunctionCall[ReturnType] = _FunctionCall._new_hydrated(function_call_id, self.client, metadata)
1611
- return fc
1612
-
1613
1546
  async def _call_function(self, args, kwargs) -> ReturnType:
1614
1547
  invocation: Union[_Invocation, _InputPlaneInvocation]
1615
1548
  if self._input_plane_url:
@@ -1856,7 +1789,6 @@ Use the `Function.get_web_url()` method instead.
1856
1789
  starmap = MethodWithAio(_starmap_sync, _starmap_async, synchronizer)
1857
1790
  for_each = MethodWithAio(_for_each_sync, _for_each_async, synchronizer)
1858
1791
  spawn_map = MethodWithAio(_spawn_map_sync, _spawn_map_async, synchronizer)
1859
- experimental_spawn_map = MethodWithAio(_experimental_spawn_map_sync, _experimental_spawn_map_async, synchronizer)
1860
1792
 
1861
1793
 
1862
1794
  class _FunctionCall(typing.Generic[ReturnType], _Object, type_prefix="fc"):
@@ -1871,28 +1803,12 @@ class _FunctionCall(typing.Generic[ReturnType], _Object, type_prefix="fc"):
1871
1803
  """
1872
1804
 
1873
1805
  _is_generator: bool = False
1874
- _num_inputs: Optional[int] = None
1875
1806
 
1876
1807
  def _invocation(self):
1877
1808
  return _Invocation(self.client.stub, self.object_id, self.client)
1878
1809
 
1879
- def _hydrate_metadata(self, metadata: Optional[Message]):
1880
- if not metadata:
1881
- return
1882
- assert isinstance(metadata, api_pb2.FunctionCallFromIdResponse)
1883
- self._num_inputs = metadata.num_inputs
1884
-
1885
- @live_method
1886
- async def num_inputs(self) -> int:
1887
- """Get the number of inputs in the function call."""
1888
- # Should have been hydrated.
1889
- assert self._num_inputs is not None
1890
- return self._num_inputs
1891
-
1892
- async def get(self, timeout: Optional[float] = None, *, index: int = 0) -> ReturnType:
1893
- """Get the result of the index-th input of the function call.
1894
- `.spawn()` calls have a single output, so only specifying `index=0` is valid.
1895
- A non-zero index is useful when your function has multiple outputs, like via `.spawn_map()`.
1810
+ async def get(self, timeout: Optional[float] = None) -> ReturnType:
1811
+ """Get the result of the function call.
1896
1812
 
1897
1813
  This function waits indefinitely by default. It takes an optional
1898
1814
  `timeout` argument that specifies the maximum number of seconds to wait,
@@ -1900,37 +1816,7 @@ class _FunctionCall(typing.Generic[ReturnType], _Object, type_prefix="fc"):
1900
1816
 
1901
1817
  The returned coroutine is not cancellation-safe.
1902
1818
  """
1903
- return await self._invocation().poll_function(timeout=timeout, index=index)
1904
-
1905
- @live_method_gen
1906
- async def iter(self, *, start: int = 0, end: Optional[int] = None) -> AsyncIterator[ReturnType]:
1907
- """Iterate in-order over the results of the function call.
1908
-
1909
- Optionally, specify a range [start, end) to iterate over.
1910
-
1911
- Example:
1912
- ```python
1913
- @app.function()
1914
- def my_func(a):
1915
- return a ** 2
1916
-
1917
-
1918
- @app.local_entrypoint()
1919
- def main():
1920
- fc = my_func.spawn_map([1, 2, 3, 4])
1921
- assert list(fc.iter()) == [1, 4, 9, 16]
1922
- assert list(fc.iter(start=1, end=3)) == [4, 9]
1923
- ```
1924
-
1925
- If `end` is not provided, it will iterate over all results.
1926
- """
1927
- num_inputs = await self.num_inputs()
1928
- if end is None:
1929
- end = num_inputs
1930
- if start < 0 or end > num_inputs:
1931
- raise ValueError(f"Invalid index range: {start} to {end} for {num_inputs} inputs")
1932
- async for _, item in self._invocation().enumerate(start_index=start, end_index=end):
1933
- yield item
1819
+ return await self._invocation().poll_function(timeout=timeout)
1934
1820
 
1935
1821
  async def get_call_graph(self) -> list[InputInfo]:
1936
1822
  """Returns a structure representing the call graph from a given root
@@ -1984,15 +1870,7 @@ class _FunctionCall(typing.Generic[ReturnType], _Object, type_prefix="fc"):
1984
1870
  if client is None:
1985
1871
  client = await _Client.from_env()
1986
1872
 
1987
- async def _load(self: _FunctionCall, resolver: Resolver, existing_object_id: Optional[str]):
1988
- request = api_pb2.FunctionCallFromIdRequest(function_call_id=function_call_id)
1989
- resp = await retry_transient_errors(resolver.client.stub.FunctionCallFromId, request)
1990
- self._hydrate(function_call_id, resolver.client, resp)
1991
-
1992
- rep = f"FunctionCall.from_id({function_call_id!r})"
1993
- fc: _FunctionCall[Any] = _FunctionCall._from_loader(_load, rep, hydrate_lazily=True)
1994
- # We already know the object ID, so we can set it directly
1995
- fc._object_id = function_call_id
1873
+ fc: _FunctionCall[Any] = _FunctionCall._new_hydrated(function_call_id, client, None)
1996
1874
  return fc
1997
1875
 
1998
1876
  @staticmethod
@@ -191,20 +191,9 @@ class _Object:
191
191
  def _is_id_type(cls, object_id) -> bool:
192
192
  return cls._get_type_from_id(object_id) == cls
193
193
 
194
- @classmethod
195
- def _repr(cls, name: str, environment_name: Optional[str] = None) -> str:
196
- public_cls = cls.__name__.strip("_")
197
- environment_repr = f", environment_name={environment_name!r}" if environment_name else ""
198
- return f"modal.{public_cls}.from_name({name!r}{environment_repr})"
199
-
200
194
  @classmethod
201
195
  def _new_hydrated(
202
- cls,
203
- object_id: str,
204
- client: _Client,
205
- handle_metadata: Optional[Message],
206
- is_another_app: bool = False,
207
- rep: Optional[str] = None,
196
+ cls, object_id: str, client: _Client, handle_metadata: Optional[Message], is_another_app: bool = False
208
197
  ) -> Self:
209
198
  obj_cls: type[Self]
210
199
  if cls._type_prefix is not None:
@@ -221,7 +210,7 @@ class _Object:
221
210
 
222
211
  # Instantiate provider
223
212
  obj = _Object.__new__(obj_cls)
224
- rep = rep or f"modal.{obj_cls.__name__.strip('_')}.from_id({object_id!r})"
213
+ rep = f"Object({object_id})" # TODO(erikbern): dumb
225
214
  obj._init(rep, is_another_app=is_another_app)
226
215
  obj._hydrate(object_id, client, handle_metadata)
227
216
 
@@ -282,7 +282,7 @@ class _MethodDecoratorType:
282
282
 
283
283
  # TODO(elias): fix support for coroutine type unwrapping for methods (static typing)
284
284
  def _method(
285
- _warn_parentheses_missing=None, # mdmd:line-hidden
285
+ _warn_parentheses_missing=None,
286
286
  *,
287
287
  # Set this to True if it's a non-generator function returning
288
288
  # a [sync/async] generator object
@@ -337,7 +337,7 @@ def _parse_custom_domains(custom_domains: Optional[Iterable[str]] = None) -> lis
337
337
 
338
338
 
339
339
  def _fastapi_endpoint(
340
- _warn_parentheses_missing=None, # mdmd:line-hidden
340
+ _warn_parentheses_missing=None,
341
341
  *,
342
342
  method: str = "GET", # REST method for the created endpoint.
343
343
  label: Optional[str] = None, # Label for created endpoint. Final subdomain will be <workspace>--<label>.modal.run.
@@ -400,7 +400,7 @@ def _fastapi_endpoint(
400
400
 
401
401
 
402
402
  def _web_endpoint(
403
- _warn_parentheses_missing=None, # mdmd:line-hidden
403
+ _warn_parentheses_missing=None,
404
404
  *,
405
405
  method: str = "GET", # REST method for the created endpoint.
406
406
  label: Optional[str] = None, # Label for created endpoint. Final subdomain will be <workspace>--<label>.modal.run.
@@ -468,7 +468,7 @@ def _web_endpoint(
468
468
 
469
469
 
470
470
  def _asgi_app(
471
- _warn_parentheses_missing=None, # mdmd:line-hidden
471
+ _warn_parentheses_missing=None,
472
472
  *,
473
473
  label: Optional[str] = None, # Label for created endpoint. Final subdomain will be <workspace>--<label>.modal.run.
474
474
  custom_domains: Optional[Iterable[str]] = None, # Deploy this endpoint on a custom domain.
@@ -525,7 +525,7 @@ def _asgi_app(
525
525
 
526
526
 
527
527
  def _wsgi_app(
528
- _warn_parentheses_missing=None, # mdmd:line-hidden
528
+ _warn_parentheses_missing=None,
529
529
  *,
530
530
  label: Optional[str] = None, # Label for created endpoint. Final subdomain will be <workspace>--<label>.modal.run.
531
531
  custom_domains: Optional[Iterable[str]] = None, # Deploy this endpoint on a custom domain.
@@ -645,7 +645,7 @@ def _web_server(
645
645
 
646
646
 
647
647
  def _enter(
648
- _warn_parentheses_missing=None, # mdmd:line-hidden
648
+ _warn_parentheses_missing=None,
649
649
  *,
650
650
  snap: bool = False,
651
651
  ) -> Callable[[Union[_PartialFunction, NullaryMethod]], _PartialFunction]:
@@ -696,7 +696,7 @@ def _exit(_warn_parentheses_missing=None) -> Callable[[NullaryMethod], _PartialF
696
696
 
697
697
 
698
698
  def _batched(
699
- _warn_parentheses_missing=None, # mdmd:line-hidden
699
+ _warn_parentheses_missing=None,
700
700
  *,
701
701
  max_batch_size: int,
702
702
  wait_ms: int,
@@ -758,7 +758,7 @@ def _batched(
758
758
 
759
759
 
760
760
  def _concurrent(
761
- _warn_parentheses_missing=None, # mdmd:line-hidden
761
+ _warn_parentheses_missing=None,
762
762
  *,
763
763
  max_inputs: int, # Hard limit on each container's input concurrency
764
764
  target_inputs: Optional[int] = None, # Input concurrency that Modal's autoscaler should target
@@ -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_attempt_token, current_function_call_id
19
+ from .execution_context import current_function_call_id
20
20
 
21
21
  FIRST_MESSAGE_TIMEOUT_SECONDS = 5.0
22
22
 
@@ -106,7 +106,6 @@ 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()
110
109
  assert function_call_id, "internal error: function_call_id not set in asgi_app() scope"
111
110
 
112
111
  messages_from_app: asyncio.Queue[dict[str, Any]] = asyncio.Queue(1)
@@ -143,7 +142,7 @@ def asgi_app_wrapper(asgi_app, container_io_manager) -> tuple[Callable[..., Asyn
143
142
  # This initial message, "http.request" or "websocket.connect", should be sent
144
143
  # immediately after starting the ASGI app's function call. If it is not received, that
145
144
  # indicates a request cancellation or other abnormal circumstance.
146
- message_gen = container_io_manager.get_data_in.aio(function_call_id, attempt_token)
145
+ message_gen = container_io_manager.get_data_in.aio(function_call_id)
147
146
  first_message_task = asyncio.create_task(message_gen.__anext__())
148
147
 
149
148
  try:
@@ -39,6 +39,7 @@ from modal.exception import ClientClosed, InputCancellation, InvalidError, Seria
39
39
  from modal_proto import api_pb2
40
40
 
41
41
  if TYPE_CHECKING:
42
+ import modal._runtime.asgi
42
43
  import modal._runtime.user_code_imports
43
44
 
44
45
 
@@ -65,7 +66,6 @@ class IOContext:
65
66
  input_ids: list[str]
66
67
  retry_counts: list[int]
67
68
  function_call_ids: list[str]
68
- attempt_tokens: list[str]
69
69
  function_inputs: list[api_pb2.FunctionInput]
70
70
  finalized_function: "modal._runtime.user_code_imports.FinalizedFunction"
71
71
 
@@ -77,7 +77,6 @@ class IOContext:
77
77
  input_ids: list[str],
78
78
  retry_counts: list[int],
79
79
  function_call_ids: list[str],
80
- attempt_tokens: list[str],
81
80
  finalized_function: "modal._runtime.user_code_imports.FinalizedFunction",
82
81
  function_inputs: list[api_pb2.FunctionInput],
83
82
  is_batched: bool,
@@ -86,7 +85,6 @@ class IOContext:
86
85
  self.input_ids = input_ids
87
86
  self.retry_counts = retry_counts
88
87
  self.function_call_ids = function_call_ids
89
- self.attempt_tokens = attempt_tokens
90
88
  self.finalized_function = finalized_function
91
89
  self.function_inputs = function_inputs
92
90
  self._is_batched = is_batched
@@ -97,11 +95,11 @@ class IOContext:
97
95
  cls,
98
96
  client: _Client,
99
97
  finalized_functions: dict[str, "modal._runtime.user_code_imports.FinalizedFunction"],
100
- inputs: list[tuple[str, int, str, str, api_pb2.FunctionInput]],
98
+ inputs: list[tuple[str, int, str, api_pb2.FunctionInput]],
101
99
  is_batched: bool,
102
100
  ) -> "IOContext":
103
101
  assert len(inputs) >= 1 if is_batched else len(inputs) == 1
104
- input_ids, retry_counts, function_call_ids, attempt_tokens, function_inputs = zip(*inputs)
102
+ input_ids, retry_counts, function_call_ids, function_inputs = zip(*inputs)
105
103
 
106
104
  async def _populate_input_blobs(client: _Client, input: api_pb2.FunctionInput) -> api_pb2.FunctionInput:
107
105
  # If we got a pointer to a blob, download it from S3.
@@ -123,7 +121,6 @@ class IOContext:
123
121
  cast(list[str], input_ids),
124
122
  cast(list[int], retry_counts),
125
123
  cast(list[str], function_call_ids),
126
- cast(list[str], attempt_tokens),
127
124
  finalized_function,
128
125
  cast(list[api_pb2.FunctionInput], function_inputs),
129
126
  is_batched,
@@ -303,7 +300,11 @@ class _ContainerIOManager:
303
300
  self.function_def = container_args.function_def
304
301
  self.checkpoint_id = container_args.checkpoint_id or None
305
302
 
306
- self.input_plane_server_url = container_args.input_plane_server_url
303
+ # We could also have the worker pass this in explicitly.
304
+ self.input_plane_server_url = None
305
+ for obj in container_args.app_layout.objects:
306
+ if obj.object_id == self.function_id:
307
+ self.input_plane_server_url = obj.function_handle_metadata.input_plane_url
307
308
 
308
309
  self.calls_completed = 0
309
310
  self.total_user_time = 0.0
@@ -483,21 +484,18 @@ class _ContainerIOManager:
483
484
  else {"data": data}
484
485
  )
485
486
 
486
- async def get_data_in(self, function_call_id: str, attempt_token: Optional[str]) -> AsyncIterator[Any]:
487
+ async def get_data_in(self, function_call_id: str) -> AsyncIterator[Any]:
487
488
  """Read from the `data_in` stream of a function call."""
488
489
  stub = self._client.stub
489
490
  if self.input_plane_server_url:
490
491
  stub = await self._client.get_stub(self.input_plane_server_url)
491
492
 
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
+ async for data in _stream_function_call_data(self._client, stub, function_call_id, "data_in"):
495
494
  yield data
496
495
 
497
496
  async def put_data_out(
498
497
  self,
499
498
  function_call_id: str,
500
- attempt_token: str,
501
499
  start_index: int,
502
500
  data_format: int,
503
501
  serialized_messages: list[Any],
@@ -518,8 +516,6 @@ class _ContainerIOManager:
518
516
  data_chunks.append(chunk)
519
517
 
520
518
  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.
523
519
 
524
520
  if self.input_plane_server_url:
525
521
  stub = await self._client.get_stub(self.input_plane_server_url)
@@ -529,7 +525,7 @@ class _ContainerIOManager:
529
525
 
530
526
  @asynccontextmanager
531
527
  async def generator_output_sender(
532
- self, function_call_id: str, attempt_token: str, data_format: int, message_rx: asyncio.Queue
528
+ self, function_call_id: str, data_format: int, message_rx: asyncio.Queue
533
529
  ) -> AsyncGenerator[None, None]:
534
530
  """Runs background task that feeds generator outputs into a function call's `data_out` stream."""
535
531
  GENERATOR_STOP_SENTINEL = Sentinel()
@@ -558,7 +554,7 @@ class _ContainerIOManager:
558
554
  else:
559
555
  serialized_messages.append(serialize_data_format(message, data_format))
560
556
  total_size += len(serialized_messages[-1]) + 512 # 512 bytes for estimated framing overhead
561
- await self.put_data_out(function_call_id, attempt_token, index, data_format, serialized_messages)
557
+ await self.put_data_out(function_call_id, index, data_format, serialized_messages)
562
558
  index += len(serialized_messages)
563
559
 
564
560
  task = asyncio.create_task(generator_output_task())
@@ -594,7 +590,7 @@ class _ContainerIOManager:
594
590
  self,
595
591
  batch_max_size: int,
596
592
  batch_wait_ms: int,
597
- ) -> AsyncIterator[list[tuple[str, int, str, str, api_pb2.FunctionInput]]]:
593
+ ) -> AsyncIterator[list[tuple[str, int, str, api_pb2.FunctionInput]]]:
598
594
  request = api_pb2.FunctionGetInputsRequest(function_id=self.function_id)
599
595
  iteration = 0
600
596
  while self._fetching_inputs:
@@ -629,9 +625,7 @@ class _ContainerIOManager:
629
625
  if item.kill_switch:
630
626
  logger.debug(f"Task {self.task_id} input kill signal input.")
631
627
  return
632
- inputs.append(
633
- (item.input_id, item.retry_count, item.function_call_id, item.attempt_token, item.input)
634
- )
628
+ inputs.append((item.input_id, item.retry_count, item.function_call_id, item.input))
635
629
  if item.input.final_input:
636
630
  if request.batch_max_size > 0:
637
631
  logger.debug(f"Task {self.task_id} Final input not expected in batch input stream")