modal 1.1.2.dev5__tar.gz → 1.1.2.dev7__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.

Potentially problematic release.


This version of modal might be problematic. Click here for more details.

Files changed (188) hide show
  1. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/PKG-INFO +1 -1
  2. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/_runtime/container_io_manager.py +1 -5
  3. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/client.pyi +2 -2
  4. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/functions.pyi +6 -6
  5. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/parallel_map.py +202 -101
  6. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/parallel_map.pyi +63 -0
  7. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal.egg-info/PKG-INFO +1 -1
  8. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal_version/__init__.py +1 -1
  9. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/LICENSE +0 -0
  10. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/README.md +0 -0
  11. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/__init__.py +0 -0
  12. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/__main__.py +0 -0
  13. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/_clustered_functions.py +0 -0
  14. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/_clustered_functions.pyi +0 -0
  15. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/_container_entrypoint.py +0 -0
  16. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/_functions.py +0 -0
  17. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/_ipython.py +0 -0
  18. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/_location.py +0 -0
  19. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/_object.py +0 -0
  20. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/_output.py +0 -0
  21. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/_partial_function.py +0 -0
  22. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/_pty.py +0 -0
  23. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/_resolver.py +0 -0
  24. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/_resources.py +0 -0
  25. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/_runtime/__init__.py +0 -0
  26. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/_runtime/asgi.py +0 -0
  27. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/_runtime/container_io_manager.pyi +0 -0
  28. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/_runtime/execution_context.py +0 -0
  29. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/_runtime/execution_context.pyi +0 -0
  30. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/_runtime/gpu_memory_snapshot.py +0 -0
  31. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/_runtime/telemetry.py +0 -0
  32. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/_runtime/user_code_imports.py +0 -0
  33. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/_serialization.py +0 -0
  34. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/_traceback.py +0 -0
  35. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/_tunnel.py +0 -0
  36. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/_tunnel.pyi +0 -0
  37. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/_type_manager.py +0 -0
  38. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/_utils/__init__.py +0 -0
  39. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/_utils/app_utils.py +0 -0
  40. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/_utils/async_utils.py +0 -0
  41. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/_utils/auth_token_manager.py +0 -0
  42. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/_utils/blob_utils.py +0 -0
  43. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/_utils/bytes_io_segment_payload.py +0 -0
  44. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/_utils/deprecation.py +0 -0
  45. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/_utils/docker_utils.py +0 -0
  46. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/_utils/function_utils.py +0 -0
  47. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/_utils/git_utils.py +0 -0
  48. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/_utils/grpc_testing.py +0 -0
  49. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/_utils/grpc_utils.py +0 -0
  50. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/_utils/hash_utils.py +0 -0
  51. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/_utils/http_utils.py +0 -0
  52. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/_utils/jwt_utils.py +0 -0
  53. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/_utils/logger.py +0 -0
  54. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/_utils/mount_utils.py +0 -0
  55. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/_utils/name_utils.py +0 -0
  56. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/_utils/package_utils.py +0 -0
  57. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/_utils/pattern_utils.py +0 -0
  58. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/_utils/rand_pb_testing.py +0 -0
  59. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/_utils/shell_utils.py +0 -0
  60. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/_utils/time_utils.py +0 -0
  61. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/_vendor/__init__.py +0 -0
  62. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/_vendor/a2wsgi_wsgi.py +0 -0
  63. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/_vendor/cloudpickle.py +0 -0
  64. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/_vendor/tblib.py +0 -0
  65. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/_watcher.py +0 -0
  66. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/app.py +0 -0
  67. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/app.pyi +0 -0
  68. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/builder/2023.12.312.txt +0 -0
  69. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/builder/2023.12.txt +0 -0
  70. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/builder/2024.04.txt +0 -0
  71. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/builder/2024.10.txt +0 -0
  72. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/builder/2025.06.txt +0 -0
  73. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/builder/PREVIEW.txt +0 -0
  74. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/builder/README.md +0 -0
  75. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/builder/base-images.json +0 -0
  76. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/call_graph.py +0 -0
  77. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/cli/__init__.py +0 -0
  78. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/cli/_download.py +0 -0
  79. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/cli/_traceback.py +0 -0
  80. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/cli/app.py +0 -0
  81. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/cli/cluster.py +0 -0
  82. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/cli/config.py +0 -0
  83. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/cli/container.py +0 -0
  84. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/cli/dict.py +0 -0
  85. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/cli/entry_point.py +0 -0
  86. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/cli/environment.py +0 -0
  87. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/cli/import_refs.py +0 -0
  88. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/cli/launch.py +0 -0
  89. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/cli/network_file_system.py +0 -0
  90. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/cli/profile.py +0 -0
  91. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/cli/programs/__init__.py +0 -0
  92. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/cli/programs/run_jupyter.py +0 -0
  93. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/cli/programs/vscode.py +0 -0
  94. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/cli/queues.py +0 -0
  95. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/cli/run.py +0 -0
  96. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/cli/secret.py +0 -0
  97. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/cli/token.py +0 -0
  98. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/cli/utils.py +0 -0
  99. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/cli/volume.py +0 -0
  100. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/client.py +0 -0
  101. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/cloud_bucket_mount.py +0 -0
  102. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/cloud_bucket_mount.pyi +0 -0
  103. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/cls.py +0 -0
  104. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/cls.pyi +0 -0
  105. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/config.py +0 -0
  106. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/container_process.py +0 -0
  107. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/container_process.pyi +0 -0
  108. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/dict.py +0 -0
  109. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/dict.pyi +0 -0
  110. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/environments.py +0 -0
  111. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/environments.pyi +0 -0
  112. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/exception.py +0 -0
  113. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/experimental/__init__.py +0 -0
  114. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/experimental/flash.py +0 -0
  115. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/experimental/flash.pyi +0 -0
  116. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/experimental/ipython.py +0 -0
  117. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/file_io.py +0 -0
  118. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/file_io.pyi +0 -0
  119. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/file_pattern_matcher.py +0 -0
  120. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/functions.py +0 -0
  121. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/gpu.py +0 -0
  122. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/image.py +0 -0
  123. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/image.pyi +0 -0
  124. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/io_streams.py +0 -0
  125. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/io_streams.pyi +0 -0
  126. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/mount.py +0 -0
  127. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/mount.pyi +0 -0
  128. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/network_file_system.py +0 -0
  129. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/network_file_system.pyi +0 -0
  130. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/object.py +0 -0
  131. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/object.pyi +0 -0
  132. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/output.py +0 -0
  133. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/partial_function.py +0 -0
  134. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/partial_function.pyi +0 -0
  135. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/proxy.py +0 -0
  136. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/proxy.pyi +0 -0
  137. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/py.typed +0 -0
  138. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/queue.py +0 -0
  139. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/queue.pyi +0 -0
  140. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/retries.py +0 -0
  141. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/runner.py +0 -0
  142. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/runner.pyi +0 -0
  143. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/running_app.py +0 -0
  144. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/sandbox.py +0 -0
  145. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/sandbox.pyi +0 -0
  146. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/schedule.py +0 -0
  147. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/scheduler_placement.py +0 -0
  148. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/secret.py +0 -0
  149. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/secret.pyi +0 -0
  150. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/serving.py +0 -0
  151. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/serving.pyi +0 -0
  152. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/snapshot.py +0 -0
  153. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/snapshot.pyi +0 -0
  154. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/stream_type.py +0 -0
  155. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/token_flow.py +0 -0
  156. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/token_flow.pyi +0 -0
  157. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/volume.py +0 -0
  158. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal/volume.pyi +0 -0
  159. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal.egg-info/SOURCES.txt +0 -0
  160. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal.egg-info/dependency_links.txt +0 -0
  161. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal.egg-info/entry_points.txt +0 -0
  162. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal.egg-info/requires.txt +0 -0
  163. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal.egg-info/top_level.txt +0 -0
  164. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal_docs/__init__.py +0 -0
  165. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal_docs/gen_cli_docs.py +0 -0
  166. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal_docs/gen_reference_docs.py +0 -0
  167. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal_docs/mdmd/__init__.py +0 -0
  168. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal_docs/mdmd/mdmd.py +0 -0
  169. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal_docs/mdmd/signatures.py +0 -0
  170. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal_proto/__init__.py +0 -0
  171. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal_proto/api.proto +0 -0
  172. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal_proto/api_grpc.py +0 -0
  173. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal_proto/api_pb2.py +0 -0
  174. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal_proto/api_pb2.pyi +0 -0
  175. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal_proto/api_pb2_grpc.py +0 -0
  176. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal_proto/api_pb2_grpc.pyi +0 -0
  177. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal_proto/modal_api_grpc.py +0 -0
  178. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal_proto/modal_options_grpc.py +0 -0
  179. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal_proto/options.proto +0 -0
  180. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal_proto/options_grpc.py +0 -0
  181. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal_proto/options_pb2.py +0 -0
  182. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal_proto/options_pb2.pyi +0 -0
  183. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal_proto/options_pb2_grpc.py +0 -0
  184. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal_proto/options_pb2_grpc.pyi +0 -0
  185. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal_proto/py.typed +0 -0
  186. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/modal_version/__main__.py +0 -0
  187. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/pyproject.toml +0 -0
  188. {modal-1.1.2.dev5 → modal-1.1.2.dev7}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.1.2.dev5
3
+ Version: 1.1.2.dev7
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License: Apache-2.0
@@ -300,11 +300,7 @@ class _ContainerIOManager:
300
300
  self.function_def = container_args.function_def
301
301
  self.checkpoint_id = container_args.checkpoint_id or None
302
302
 
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
303
+ self.input_plane_server_url = container_args.input_plane_server_url
308
304
 
309
305
  self.calls_completed = 0
310
306
  self.total_user_time = 0.0
@@ -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.dev5",
36
+ version: str = "1.1.2.dev7",
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.dev5",
167
+ version: str = "1.1.2.dev7",
168
168
  ):
169
169
  """mdmd:hidden
170
170
  The Modal client object is not intended to be instantiated directly by users.
@@ -427,7 +427,7 @@ class Function(
427
427
 
428
428
  _call_generator: ___call_generator_spec[typing_extensions.Self]
429
429
 
430
- class __remote_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER, SUPERSELF]):
430
+ class __remote_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER, SUPERSELF]):
431
431
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> ReturnType_INNER:
432
432
  """Calls the function remotely, executing it with the given arguments and returning the execution's result."""
433
433
  ...
@@ -436,7 +436,7 @@ class Function(
436
436
  """Calls the function remotely, executing it with the given arguments and returning the execution's result."""
437
437
  ...
438
438
 
439
- remote: __remote_spec[modal._functions.ReturnType, modal._functions.P, typing_extensions.Self]
439
+ remote: __remote_spec[modal._functions.P, modal._functions.ReturnType, typing_extensions.Self]
440
440
 
441
441
  class __remote_gen_spec(typing_extensions.Protocol[SUPERSELF]):
442
442
  def __call__(self, /, *args, **kwargs) -> typing.Generator[typing.Any, None, None]:
@@ -463,7 +463,7 @@ class Function(
463
463
  """
464
464
  ...
465
465
 
466
- class ___experimental_spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER, SUPERSELF]):
466
+ class ___experimental_spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER, SUPERSELF]):
467
467
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
468
468
  """[Experimental] Calls the function with the given arguments, without waiting for the results.
469
469
 
@@ -487,7 +487,7 @@ class Function(
487
487
  ...
488
488
 
489
489
  _experimental_spawn: ___experimental_spawn_spec[
490
- modal._functions.ReturnType, modal._functions.P, typing_extensions.Self
490
+ modal._functions.P, modal._functions.ReturnType, typing_extensions.Self
491
491
  ]
492
492
 
493
493
  class ___spawn_map_inner_spec(typing_extensions.Protocol[P_INNER, SUPERSELF]):
@@ -496,7 +496,7 @@ class Function(
496
496
 
497
497
  _spawn_map_inner: ___spawn_map_inner_spec[modal._functions.P, typing_extensions.Self]
498
498
 
499
- class __spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER, SUPERSELF]):
499
+ class __spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER, SUPERSELF]):
500
500
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
501
501
  """Calls the function with the given arguments, without waiting for the results.
502
502
 
@@ -517,7 +517,7 @@ class Function(
517
517
  """
518
518
  ...
519
519
 
520
- spawn: __spawn_spec[modal._functions.ReturnType, modal._functions.P, typing_extensions.Self]
520
+ spawn: __spawn_spec[modal._functions.P, modal._functions.ReturnType, typing_extensions.Self]
521
521
 
522
522
  def get_raw_f(self) -> collections.abc.Callable[..., typing.Any]:
523
523
  """Return the inner Python object wrapped by this Modal Function."""
@@ -86,6 +86,180 @@ if typing.TYPE_CHECKING:
86
86
  import modal.functions
87
87
 
88
88
 
89
+ class InputPreprocessor:
90
+ """
91
+ Constructs FunctionPutInputsItem objects from the raw-input queue, and puts them in the processed-input queue.
92
+ """
93
+
94
+ def __init__(
95
+ self,
96
+ client: "modal.client._Client",
97
+ *,
98
+ raw_input_queue: _SynchronizedQueue,
99
+ processed_input_queue: asyncio.Queue,
100
+ function: "modal.functions._Function",
101
+ created_callback: Callable[[int], None],
102
+ done_callback: Callable[[], None],
103
+ ):
104
+ self.client = client
105
+ self.function = function
106
+ self.inputs_created = 0
107
+ self.raw_input_queue = raw_input_queue
108
+ self.processed_input_queue = processed_input_queue
109
+ self.created_callback = created_callback
110
+ self.done_callback = done_callback
111
+
112
+ async def input_iter(self):
113
+ while 1:
114
+ raw_input = await self.raw_input_queue.get()
115
+ if raw_input is None: # end of input sentinel
116
+ break
117
+ yield raw_input # args, kwargs
118
+
119
+ def create_input_factory(self):
120
+ async def create_input(argskwargs):
121
+ idx = self.inputs_created
122
+ self.inputs_created += 1
123
+ self.created_callback(self.inputs_created)
124
+ (args, kwargs) = argskwargs
125
+ return await _create_input(
126
+ args,
127
+ kwargs,
128
+ self.client.stub,
129
+ max_object_size_bytes=self.function._max_object_size_bytes,
130
+ idx=idx,
131
+ method_name=self.function._use_method_name,
132
+ )
133
+
134
+ return create_input
135
+
136
+ async def drain_input_generator(self):
137
+ # Parallelize uploading blobs
138
+ async with aclosing(
139
+ async_map_ordered(self.input_iter(), self.create_input_factory(), concurrency=BLOB_MAX_PARALLELISM)
140
+ ) as streamer:
141
+ async for item in streamer:
142
+ await self.processed_input_queue.put(item)
143
+
144
+ # close queue iterator
145
+ await self.processed_input_queue.put(None)
146
+ self.done_callback()
147
+ yield
148
+
149
+
150
+ class InputPumper:
151
+ """
152
+ Reads inputs from a queue of FunctionPutInputsItems, and sends them to the server.
153
+ """
154
+
155
+ def __init__(
156
+ self,
157
+ client: "modal.client._Client",
158
+ *,
159
+ input_queue: asyncio.Queue,
160
+ function: "modal.functions._Function",
161
+ function_call_id: str,
162
+ map_items_manager: Optional["_MapItemsManager"] = None,
163
+ ):
164
+ self.client = client
165
+ self.function = function
166
+ self.map_items_manager = map_items_manager
167
+ self.input_queue = input_queue
168
+ self.inputs_sent = 0
169
+ self.function_call_id = function_call_id
170
+
171
+ async def pump_inputs(self):
172
+ assert self.client.stub
173
+ async for items in queue_batch_iterator(self.input_queue, max_batch_size=MAP_INVOCATION_CHUNK_SIZE):
174
+ # Add items to the manager. Their state will be SENDING.
175
+ if self.map_items_manager is not None:
176
+ await self.map_items_manager.add_items(items)
177
+ request = api_pb2.FunctionPutInputsRequest(
178
+ function_id=self.function.object_id,
179
+ inputs=items,
180
+ function_call_id=self.function_call_id,
181
+ )
182
+ logger.debug(
183
+ f"Pushing {len(items)} inputs to server. Num queued inputs awaiting"
184
+ f" push is {self.input_queue.qsize()}. "
185
+ )
186
+
187
+ resp = await self._send_inputs(self.client.stub.FunctionPutInputs, request)
188
+ self.inputs_sent += len(items)
189
+ # Change item state to WAITING_FOR_OUTPUT, and set the input_id and input_jwt which are in the response.
190
+ if self.map_items_manager is not None:
191
+ self.map_items_manager.handle_put_inputs_response(resp.inputs)
192
+ logger.debug(
193
+ f"Successfully pushed {len(items)} inputs to server. "
194
+ f"Num queued inputs awaiting push is {self.input_queue.qsize()}."
195
+ )
196
+ yield
197
+
198
+ async def _send_inputs(
199
+ self,
200
+ fn: "modal.client.UnaryUnaryWrapper",
201
+ request: typing.Union[api_pb2.FunctionPutInputsRequest, api_pb2.FunctionRetryInputsRequest],
202
+ ) -> typing.Union[api_pb2.FunctionPutInputsResponse, api_pb2.FunctionRetryInputsResponse]:
203
+ # with 8 retries we log the warning below about every 30 seconds which isn't too spammy.
204
+ retry_warning_message = RetryWarningMessage(
205
+ message=f"Warning: map progress for function {self.function._function_name} is limited."
206
+ " Common bottlenecks include slow iteration over results, or function backlogs.",
207
+ warning_interval=8,
208
+ errors_to_warn_for=[Status.RESOURCE_EXHAUSTED],
209
+ )
210
+ return await retry_transient_errors(
211
+ fn,
212
+ request,
213
+ max_retries=None,
214
+ max_delay=PUMP_INPUTS_MAX_RETRY_DELAY,
215
+ additional_status_codes=[Status.RESOURCE_EXHAUSTED],
216
+ retry_warning_message=retry_warning_message,
217
+ )
218
+
219
+
220
+ class SyncInputPumper(InputPumper):
221
+ def __init__(
222
+ self,
223
+ client: "modal.client._Client",
224
+ *,
225
+ input_queue: asyncio.Queue,
226
+ retry_queue: TimestampPriorityQueue,
227
+ function: "modal.functions._Function",
228
+ function_call_jwt: str,
229
+ function_call_id: str,
230
+ map_items_manager: "_MapItemsManager",
231
+ ):
232
+ super().__init__(
233
+ client,
234
+ input_queue=input_queue,
235
+ function=function,
236
+ function_call_id=function_call_id,
237
+ map_items_manager=map_items_manager,
238
+ )
239
+ self.retry_queue = retry_queue
240
+ self.inputs_retried = 0
241
+ self.function_call_jwt = function_call_jwt
242
+
243
+ async def retry_inputs(self):
244
+ async for retriable_idxs in queue_batch_iterator(self.retry_queue, max_batch_size=MAP_INVOCATION_CHUNK_SIZE):
245
+ # For each index, use the context in the manager to create a FunctionRetryInputsItem.
246
+ # This will also update the context state to RETRYING.
247
+ inputs: list[api_pb2.FunctionRetryInputsItem] = await self.map_items_manager.prepare_items_for_retry(
248
+ retriable_idxs
249
+ )
250
+ request = api_pb2.FunctionRetryInputsRequest(
251
+ function_call_jwt=self.function_call_jwt,
252
+ inputs=inputs,
253
+ )
254
+ resp = await self._send_inputs(self.client.stub.FunctionRetryInputs, request)
255
+ # Update the state to WAITING_FOR_OUTPUT, and update the input_jwt in the context
256
+ # to the new value in the response.
257
+ self.map_items_manager.handle_retry_response(resp.input_jwts)
258
+ logger.debug(f"Successfully pushed retry for {len(inputs)} to server.")
259
+ self.inputs_retried += len(inputs)
260
+ yield
261
+
262
+
89
263
  async def _map_invocation(
90
264
  function: "modal.functions._Function",
91
265
  raw_input_queue: _SynchronizedQueue,
@@ -117,8 +291,6 @@ async def _map_invocation(
117
291
  have_all_inputs = False
118
292
  map_done_event = asyncio.Event()
119
293
  inputs_created = 0
120
- inputs_sent = 0
121
- inputs_retried = 0
122
294
  outputs_completed = 0
123
295
  outputs_received = 0
124
296
  retried_outputs = 0
@@ -135,25 +307,24 @@ async def _map_invocation(
135
307
  retry_policy, function_call_invocation_type, retry_queue, sync_client_retries_enabled, max_inputs_outstanding
136
308
  )
137
309
 
138
- async def create_input(argskwargs):
139
- idx = inputs_created
140
- update_state(set_inputs_created=inputs_created + 1)
141
- (args, kwargs) = argskwargs
142
- return await _create_input(
143
- args,
144
- kwargs,
145
- client.stub,
146
- max_object_size_bytes=function._max_object_size_bytes,
147
- idx=idx,
148
- method_name=function._use_method_name,
149
- )
310
+ input_preprocessor = InputPreprocessor(
311
+ client=client,
312
+ raw_input_queue=raw_input_queue,
313
+ processed_input_queue=input_queue,
314
+ function=function,
315
+ created_callback=lambda x: update_state(set_inputs_created=x),
316
+ done_callback=lambda: update_state(set_have_all_inputs=True),
317
+ )
150
318
 
151
- async def input_iter():
152
- while 1:
153
- raw_input = await raw_input_queue.get()
154
- if raw_input is None: # end of input sentinel
155
- break
156
- yield raw_input # args, kwargs
319
+ input_pumper = SyncInputPumper(
320
+ client=client,
321
+ input_queue=input_queue,
322
+ retry_queue=retry_queue,
323
+ function=function,
324
+ map_items_manager=map_items_manager,
325
+ function_call_jwt=function_call_jwt,
326
+ function_call_id=function_call_id,
327
+ )
157
328
 
158
329
  def update_state(set_have_all_inputs=None, set_inputs_created=None, set_outputs_completed=None):
159
330
  # This should be the only method that needs nonlocal of the following vars
@@ -175,84 +346,6 @@ async def _map_invocation(
175
346
  # map is done
176
347
  map_done_event.set()
177
348
 
178
- async def drain_input_generator():
179
- # Parallelize uploading blobs
180
- async with aclosing(
181
- async_map_ordered(input_iter(), create_input, concurrency=BLOB_MAX_PARALLELISM)
182
- ) as streamer:
183
- async for item in streamer:
184
- await input_queue.put(item)
185
-
186
- # close queue iterator
187
- await input_queue.put(None)
188
- update_state(set_have_all_inputs=True)
189
- yield
190
-
191
- async def pump_inputs():
192
- assert client.stub
193
- nonlocal inputs_sent
194
- async for items in queue_batch_iterator(input_queue, max_batch_size=MAP_INVOCATION_CHUNK_SIZE):
195
- # Add items to the manager. Their state will be SENDING.
196
- await map_items_manager.add_items(items)
197
- request = api_pb2.FunctionPutInputsRequest(
198
- function_id=function.object_id,
199
- inputs=items,
200
- function_call_id=function_call_id,
201
- )
202
- logger.debug(
203
- f"Pushing {len(items)} inputs to server. Num queued inputs awaiting push is {input_queue.qsize()}."
204
- )
205
-
206
- resp = await send_inputs(client.stub.FunctionPutInputs, request)
207
- inputs_sent += len(items)
208
- # Change item state to WAITING_FOR_OUTPUT, and set the input_id and input_jwt which are in the response.
209
- map_items_manager.handle_put_inputs_response(resp.inputs)
210
- logger.debug(
211
- f"Successfully pushed {len(items)} inputs to server. "
212
- f"Num queued inputs awaiting push is {input_queue.qsize()}."
213
- )
214
- yield
215
-
216
- async def retry_inputs():
217
- nonlocal inputs_retried
218
- async for retriable_idxs in queue_batch_iterator(retry_queue, max_batch_size=MAP_INVOCATION_CHUNK_SIZE):
219
- # For each index, use the context in the manager to create a FunctionRetryInputsItem.
220
- # This will also update the context state to RETRYING.
221
- inputs: list[api_pb2.FunctionRetryInputsItem] = await map_items_manager.prepare_items_for_retry(
222
- retriable_idxs
223
- )
224
- request = api_pb2.FunctionRetryInputsRequest(
225
- function_call_jwt=function_call_jwt,
226
- inputs=inputs,
227
- )
228
- resp = await send_inputs(client.stub.FunctionRetryInputs, request)
229
- # Update the state to WAITING_FOR_OUTPUT, and update the input_jwt in the context
230
- # to the new value in the response.
231
- map_items_manager.handle_retry_response(resp.input_jwts)
232
- logger.debug(f"Successfully pushed retry for {len(inputs)} to server.")
233
- inputs_retried += len(inputs)
234
- yield
235
-
236
- async def send_inputs(
237
- fn: "modal.client.UnaryUnaryWrapper",
238
- request: typing.Union[api_pb2.FunctionPutInputsRequest, api_pb2.FunctionRetryInputsRequest],
239
- ) -> typing.Union[api_pb2.FunctionPutInputsResponse, api_pb2.FunctionRetryInputsResponse]:
240
- # with 8 retries we log the warning below about every 30 seconds which isn't too spammy.
241
- retry_warning_message = RetryWarningMessage(
242
- message=f"Warning: map progress for function {function._function_name} is limited."
243
- " Common bottlenecks include slow iteration over results, or function backlogs.",
244
- warning_interval=8,
245
- errors_to_warn_for=[Status.RESOURCE_EXHAUSTED],
246
- )
247
- return await retry_transient_errors(
248
- fn,
249
- request,
250
- max_retries=None,
251
- max_delay=PUMP_INPUTS_MAX_RETRY_DELAY,
252
- additional_status_codes=[Status.RESOURCE_EXHAUSTED],
253
- retry_warning_message=retry_warning_message,
254
- )
255
-
256
349
  async def get_all_outputs():
257
350
  assert client.stub
258
351
  nonlocal \
@@ -395,8 +488,11 @@ async def _map_invocation(
395
488
  def log_stats():
396
489
  logger.debug(
397
490
  f"Map stats: sync_client_retries_enabled={sync_client_retries_enabled} "
398
- f"have_all_inputs={have_all_inputs} inputs_created={inputs_created} input_sent={inputs_sent} "
399
- f"inputs_retried={inputs_retried} outputs_received={outputs_received} "
491
+ f"have_all_inputs={have_all_inputs} "
492
+ f"inputs_created={inputs_created} "
493
+ f"input_sent={input_pumper.inputs_sent} "
494
+ f"inputs_retried={input_pumper.inputs_retried} "
495
+ f"outputs_received={outputs_received} "
400
496
  f"successful_completions={successful_completions} failed_completions={failed_completions} "
401
497
  f"no_context_duplicates={no_context_duplicates} old_retry_duplicates={stale_retry_duplicates} "
402
498
  f"already_complete_duplicates={already_complete_duplicates} "
@@ -415,7 +511,12 @@ async def _map_invocation(
415
511
 
416
512
  log_debug_stats_task = asyncio.create_task(log_debug_stats())
417
513
  async with aclosing(
418
- async_merge(drain_input_generator(), pump_inputs(), poll_outputs(), retry_inputs())
514
+ async_merge(
515
+ input_preprocessor.drain_input_generator(),
516
+ input_pumper.pump_inputs(),
517
+ input_pumper.retry_inputs(),
518
+ poll_outputs(),
519
+ )
419
520
  ) as streamer:
420
521
  async for response in streamer:
421
522
  if response is not None: # type: ignore[unreachable]
@@ -1,5 +1,6 @@
1
1
  import asyncio
2
2
  import asyncio.events
3
+ import asyncio.queues
3
4
  import collections.abc
4
5
  import enum
5
6
  import modal._functions
@@ -60,6 +61,68 @@ class _OutputValue:
60
61
  """Return self==value."""
61
62
  ...
62
63
 
64
+ class InputPreprocessor:
65
+ """Constructs FunctionPutInputsItem objects from the raw-input queue, and puts them in the processed-input queue."""
66
+ def __init__(
67
+ self,
68
+ client: modal.client._Client,
69
+ *,
70
+ raw_input_queue: _SynchronizedQueue,
71
+ processed_input_queue: asyncio.queues.Queue,
72
+ function: modal._functions._Function,
73
+ created_callback: collections.abc.Callable[[int], None],
74
+ done_callback: collections.abc.Callable[[], None],
75
+ ):
76
+ """Initialize self. See help(type(self)) for accurate signature."""
77
+ ...
78
+
79
+ def input_iter(self): ...
80
+ def create_input_factory(self): ...
81
+ def drain_input_generator(self): ...
82
+
83
+ class InputPumper:
84
+ """Reads inputs from a queue of FunctionPutInputsItems, and sends them to the server."""
85
+ def __init__(
86
+ self,
87
+ client: modal.client._Client,
88
+ *,
89
+ input_queue: asyncio.queues.Queue,
90
+ function: modal._functions._Function,
91
+ function_call_id: str,
92
+ map_items_manager: typing.Optional[_MapItemsManager] = None,
93
+ ):
94
+ """Initialize self. See help(type(self)) for accurate signature."""
95
+ ...
96
+
97
+ def pump_inputs(self): ...
98
+ async def _send_inputs(
99
+ self,
100
+ fn: modal.client.UnaryUnaryWrapper,
101
+ request: typing.Union[
102
+ modal_proto.api_pb2.FunctionPutInputsRequest, modal_proto.api_pb2.FunctionRetryInputsRequest
103
+ ],
104
+ ) -> typing.Union[
105
+ modal_proto.api_pb2.FunctionPutInputsResponse, modal_proto.api_pb2.FunctionRetryInputsResponse
106
+ ]: ...
107
+
108
+ class SyncInputPumper(InputPumper):
109
+ """Reads inputs from a queue of FunctionPutInputsItems, and sends them to the server."""
110
+ def __init__(
111
+ self,
112
+ client: modal.client._Client,
113
+ *,
114
+ input_queue: asyncio.queues.Queue,
115
+ retry_queue: modal._utils.async_utils.TimestampPriorityQueue,
116
+ function: modal._functions._Function,
117
+ function_call_jwt: str,
118
+ function_call_id: str,
119
+ map_items_manager: _MapItemsManager,
120
+ ):
121
+ """Initialize self. See help(type(self)) for accurate signature."""
122
+ ...
123
+
124
+ def retry_inputs(self): ...
125
+
63
126
  def _map_invocation(
64
127
  function: modal._functions._Function,
65
128
  raw_input_queue: _SynchronizedQueue,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.1.2.dev5
3
+ Version: 1.1.2.dev7
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.dev5"
4
+ __version__ = "1.1.2.dev7"
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