modal 1.0.4.dev4__tar.gz → 1.0.4.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.
Files changed (184) hide show
  1. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/PKG-INFO +2 -2
  2. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/_utils/async_utils.py +45 -16
  3. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/client.pyi +2 -2
  4. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/sandbox.py +7 -0
  5. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/sandbox.pyi +8 -0
  6. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/volume.py +5 -0
  7. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal.egg-info/PKG-INFO +2 -2
  8. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal.egg-info/requires.txt +1 -1
  9. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal_version/__init__.py +1 -1
  10. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/pyproject.toml +1 -1
  11. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/LICENSE +0 -0
  12. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/README.md +0 -0
  13. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/__init__.py +0 -0
  14. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/__main__.py +0 -0
  15. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/_clustered_functions.py +0 -0
  16. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/_clustered_functions.pyi +0 -0
  17. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/_container_entrypoint.py +0 -0
  18. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/_functions.py +0 -0
  19. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/_ipython.py +0 -0
  20. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/_location.py +0 -0
  21. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/_object.py +0 -0
  22. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/_output.py +0 -0
  23. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/_partial_function.py +0 -0
  24. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/_pty.py +0 -0
  25. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/_resolver.py +0 -0
  26. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/_resources.py +0 -0
  27. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/_runtime/__init__.py +0 -0
  28. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/_runtime/asgi.py +0 -0
  29. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/_runtime/container_io_manager.py +0 -0
  30. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/_runtime/container_io_manager.pyi +0 -0
  31. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/_runtime/execution_context.py +0 -0
  32. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/_runtime/execution_context.pyi +0 -0
  33. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/_runtime/gpu_memory_snapshot.py +0 -0
  34. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/_runtime/telemetry.py +0 -0
  35. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/_runtime/user_code_imports.py +0 -0
  36. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/_serialization.py +0 -0
  37. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/_traceback.py +0 -0
  38. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/_tunnel.py +0 -0
  39. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/_tunnel.pyi +0 -0
  40. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/_type_manager.py +0 -0
  41. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/_utils/__init__.py +0 -0
  42. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/_utils/app_utils.py +0 -0
  43. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/_utils/blob_utils.py +0 -0
  44. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/_utils/bytes_io_segment_payload.py +0 -0
  45. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/_utils/deprecation.py +0 -0
  46. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/_utils/docker_utils.py +0 -0
  47. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/_utils/function_utils.py +0 -0
  48. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/_utils/git_utils.py +0 -0
  49. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/_utils/grpc_testing.py +0 -0
  50. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/_utils/grpc_utils.py +0 -0
  51. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/_utils/hash_utils.py +0 -0
  52. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/_utils/http_utils.py +0 -0
  53. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/_utils/jwt_utils.py +0 -0
  54. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/_utils/logger.py +0 -0
  55. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/_utils/mount_utils.py +0 -0
  56. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/_utils/name_utils.py +0 -0
  57. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/_utils/package_utils.py +0 -0
  58. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/_utils/pattern_utils.py +0 -0
  59. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/_utils/rand_pb_testing.py +0 -0
  60. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/_utils/shell_utils.py +0 -0
  61. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/_utils/time_utils.py +0 -0
  62. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/_vendor/__init__.py +0 -0
  63. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/_vendor/a2wsgi_wsgi.py +0 -0
  64. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/_vendor/cloudpickle.py +0 -0
  65. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/_vendor/tblib.py +0 -0
  66. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/_watcher.py +0 -0
  67. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/app.py +0 -0
  68. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/app.pyi +0 -0
  69. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/call_graph.py +0 -0
  70. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/cli/__init__.py +0 -0
  71. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/cli/_download.py +0 -0
  72. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/cli/_traceback.py +0 -0
  73. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/cli/app.py +0 -0
  74. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/cli/cluster.py +0 -0
  75. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/cli/config.py +0 -0
  76. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/cli/container.py +0 -0
  77. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/cli/dict.py +0 -0
  78. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/cli/entry_point.py +0 -0
  79. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/cli/environment.py +0 -0
  80. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/cli/import_refs.py +0 -0
  81. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/cli/launch.py +0 -0
  82. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/cli/network_file_system.py +0 -0
  83. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/cli/profile.py +0 -0
  84. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/cli/programs/__init__.py +0 -0
  85. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/cli/programs/run_jupyter.py +0 -0
  86. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/cli/programs/vscode.py +0 -0
  87. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/cli/queues.py +0 -0
  88. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/cli/run.py +0 -0
  89. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/cli/secret.py +0 -0
  90. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/cli/token.py +0 -0
  91. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/cli/utils.py +0 -0
  92. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/cli/volume.py +0 -0
  93. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/client.py +0 -0
  94. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/cloud_bucket_mount.py +0 -0
  95. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/cloud_bucket_mount.pyi +0 -0
  96. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/cls.py +0 -0
  97. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/cls.pyi +0 -0
  98. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/config.py +0 -0
  99. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/container_process.py +0 -0
  100. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/container_process.pyi +0 -0
  101. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/dict.py +0 -0
  102. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/dict.pyi +0 -0
  103. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/environments.py +0 -0
  104. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/environments.pyi +0 -0
  105. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/exception.py +0 -0
  106. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/experimental/__init__.py +0 -0
  107. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/experimental/ipython.py +0 -0
  108. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/file_io.py +0 -0
  109. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/file_io.pyi +0 -0
  110. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/file_pattern_matcher.py +0 -0
  111. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/functions.py +0 -0
  112. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/functions.pyi +0 -0
  113. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/gpu.py +0 -0
  114. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/image.py +0 -0
  115. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/image.pyi +0 -0
  116. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/io_streams.py +0 -0
  117. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/io_streams.pyi +0 -0
  118. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/mount.py +0 -0
  119. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/mount.pyi +0 -0
  120. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/network_file_system.py +0 -0
  121. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/network_file_system.pyi +0 -0
  122. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/object.py +0 -0
  123. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/object.pyi +0 -0
  124. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/output.py +0 -0
  125. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/parallel_map.py +0 -0
  126. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/parallel_map.pyi +0 -0
  127. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/partial_function.py +0 -0
  128. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/partial_function.pyi +0 -0
  129. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/proxy.py +0 -0
  130. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/proxy.pyi +0 -0
  131. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/py.typed +0 -0
  132. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/queue.py +0 -0
  133. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/queue.pyi +0 -0
  134. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/requirements/2023.12.312.txt +0 -0
  135. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/requirements/2023.12.txt +0 -0
  136. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/requirements/2024.04.txt +0 -0
  137. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/requirements/2024.10.txt +0 -0
  138. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/requirements/PREVIEW.txt +0 -0
  139. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/requirements/README.md +0 -0
  140. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/requirements/base-images.json +0 -0
  141. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/retries.py +0 -0
  142. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/runner.py +0 -0
  143. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/runner.pyi +0 -0
  144. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/running_app.py +0 -0
  145. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/schedule.py +0 -0
  146. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/scheduler_placement.py +0 -0
  147. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/secret.py +0 -0
  148. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/secret.pyi +0 -0
  149. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/serving.py +0 -0
  150. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/serving.pyi +0 -0
  151. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/snapshot.py +0 -0
  152. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/snapshot.pyi +0 -0
  153. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/stream_type.py +0 -0
  154. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/token_flow.py +0 -0
  155. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/token_flow.pyi +0 -0
  156. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal/volume.pyi +0 -0
  157. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal.egg-info/SOURCES.txt +0 -0
  158. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal.egg-info/dependency_links.txt +0 -0
  159. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal.egg-info/entry_points.txt +0 -0
  160. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal.egg-info/top_level.txt +0 -0
  161. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal_docs/__init__.py +0 -0
  162. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal_docs/gen_cli_docs.py +0 -0
  163. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal_docs/gen_reference_docs.py +0 -0
  164. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal_docs/mdmd/__init__.py +0 -0
  165. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal_docs/mdmd/mdmd.py +0 -0
  166. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal_docs/mdmd/signatures.py +0 -0
  167. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal_proto/__init__.py +0 -0
  168. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal_proto/api.proto +0 -0
  169. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal_proto/api_grpc.py +0 -0
  170. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal_proto/api_pb2.py +0 -0
  171. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal_proto/api_pb2.pyi +0 -0
  172. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal_proto/api_pb2_grpc.py +0 -0
  173. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal_proto/api_pb2_grpc.pyi +0 -0
  174. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal_proto/modal_api_grpc.py +0 -0
  175. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal_proto/modal_options_grpc.py +0 -0
  176. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal_proto/options.proto +0 -0
  177. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal_proto/options_grpc.py +0 -0
  178. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal_proto/options_pb2.py +0 -0
  179. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal_proto/options_pb2.pyi +0 -0
  180. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal_proto/options_pb2_grpc.py +0 -0
  181. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal_proto/options_pb2_grpc.pyi +0 -0
  182. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal_proto/py.typed +0 -0
  183. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/modal_version/__main__.py +0 -0
  184. {modal-1.0.4.dev4 → modal-1.0.4.dev7}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.0.4.dev4
3
+ Version: 1.0.4.dev7
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.0
22
22
  Requires-Dist: grpclib==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.9.13
25
+ Requires-Dist: synchronicity~=0.9.14
26
26
  Requires-Dist: toml
27
27
  Requires-Dist: typer>=0.9
28
28
  Requires-Dist: types-certifi
@@ -647,7 +647,9 @@ class StopSentinelType: ...
647
647
  STOP_SENTINEL = StopSentinelType()
648
648
 
649
649
 
650
- async def async_merge(*generators: AsyncGenerator[T, None]) -> AsyncGenerator[T, None]:
650
+ async def async_merge(
651
+ *generators: AsyncGenerator[T, None], cancellation_timeout: float = 10.0
652
+ ) -> AsyncGenerator[T, None]:
651
653
  """
652
654
  Asynchronously merges multiple async generators into a single async generator.
653
655
 
@@ -692,8 +694,9 @@ async def async_merge(*generators: AsyncGenerator[T, None]) -> AsyncGenerator[T,
692
694
 
693
695
  async def producer(generator: AsyncGenerator[T, None]):
694
696
  try:
695
- async for item in generator:
696
- await queue.put(ValueWrapper(item))
697
+ async with aclosing(generator) as stream:
698
+ async for item in stream:
699
+ await queue.put(ValueWrapper(item))
697
700
  except Exception as e:
698
701
  await queue.put(ExceptionWrapper(e))
699
702
 
@@ -735,15 +738,20 @@ async def async_merge(*generators: AsyncGenerator[T, None]) -> AsyncGenerator[T,
735
738
  new_output_task = asyncio.create_task(queue.get())
736
739
 
737
740
  finally:
738
- if not new_output_task.done():
739
- new_output_task.cancel()
740
- for task in tasks:
741
- if not task.done():
742
- try:
743
- task.cancel()
744
- await task
745
- except asyncio.CancelledError:
746
- pass
741
+ unfinished_tasks = [t for t in tasks | {new_output_task} if not t.done()]
742
+ for t in unfinished_tasks:
743
+ t.cancel()
744
+ try:
745
+ await asyncio.wait_for(
746
+ asyncio.shield(
747
+ # we need to `shield` the `gather` to ensure cooperation with the timeout
748
+ # all underlying tasks have been marked as cancelled at this point anyway
749
+ asyncio.gather(*unfinished_tasks, return_exceptions=True)
750
+ ),
751
+ timeout=cancellation_timeout,
752
+ )
753
+ except asyncio.TimeoutError:
754
+ logger.debug("Timed out while cleaning up async_merge")
747
755
 
748
756
 
749
757
  async def callable_to_agen(awaitable: Callable[[], Awaitable[T]]) -> AsyncGenerator[T, None]:
@@ -761,16 +769,34 @@ async def gather_cancel_on_exc(*coros_or_futures):
761
769
  raise
762
770
 
763
771
 
772
+ async def prevent_cancellation_abortion(coro):
773
+ # if this is cancelled, it will wait for coro cancellation handling
774
+ # and then unconditionally re-raises a CancelledError, even if the underlying coro
775
+ # doesn't re-raise the cancellation itself
776
+ t = asyncio.create_task(coro)
777
+ try:
778
+ return await asyncio.shield(t)
779
+ except asyncio.CancelledError:
780
+ if t.cancelled():
781
+ # coro cancelled itself - reraise
782
+ raise
783
+ t.cancel() # cancel task
784
+ await t # this *normally* reraises
785
+ raise # if the above somehow resolved, by swallowing cancellation - we still raise
786
+
787
+
764
788
  async def async_map(
765
789
  input_generator: AsyncGenerator[T, None],
766
790
  async_mapper_func: Callable[[T], Awaitable[V]],
767
791
  concurrency: int,
792
+ cancellation_timeout: float = 10.0,
768
793
  ) -> AsyncGenerator[V, None]:
769
794
  queue: asyncio.Queue[Union[ValueWrapper[T], StopSentinelType]] = asyncio.Queue(maxsize=concurrency * 2)
770
795
 
771
796
  async def producer() -> AsyncGenerator[V, None]:
772
- async for item in input_generator:
773
- await queue.put(ValueWrapper(item))
797
+ async with aclosing(input_generator) as stream:
798
+ async for item in stream:
799
+ await queue.put(ValueWrapper(item))
774
800
 
775
801
  for _ in range(concurrency):
776
802
  await queue.put(STOP_SENTINEL)
@@ -784,14 +810,17 @@ async def async_map(
784
810
  while True:
785
811
  item = await queue.get()
786
812
  if isinstance(item, ValueWrapper):
787
- yield await async_mapper_func(item.value)
813
+ res = await prevent_cancellation_abortion(async_mapper_func(item.value))
814
+ yield res
788
815
  elif isinstance(item, ExceptionWrapper):
789
816
  raise item.value
790
817
  else:
791
818
  assert_type(item, StopSentinelType)
792
819
  break
793
820
 
794
- async with aclosing(async_merge(*[worker() for _ in range(concurrency)], producer())) as stream:
821
+ async with aclosing(
822
+ async_merge(*[worker() for i in range(concurrency)], producer(), cancellation_timeout=cancellation_timeout)
823
+ ) as stream:
795
824
  async for item in stream:
796
825
  yield item
797
826
 
@@ -31,7 +31,7 @@ class _Client:
31
31
  server_url: str,
32
32
  client_type: int,
33
33
  credentials: typing.Optional[tuple[str, str]],
34
- version: str = "1.0.4.dev4",
34
+ version: str = "1.0.4.dev7",
35
35
  ): ...
36
36
  def is_closed(self) -> bool: ...
37
37
  @property
@@ -94,7 +94,7 @@ class Client:
94
94
  server_url: str,
95
95
  client_type: int,
96
96
  credentials: typing.Optional[tuple[str, str]],
97
- version: str = "1.0.4.dev4",
97
+ version: str = "1.0.4.dev7",
98
98
  ): ...
99
99
  def is_closed(self) -> bool: ...
100
100
  @property
@@ -105,6 +105,7 @@ class _Sandbox(_Object, type_prefix="sb"):
105
105
  proxy: Optional[_Proxy] = None,
106
106
  _experimental_scheduler_placement: Optional[SchedulerPlacement] = None,
107
107
  enable_snapshot: bool = False,
108
+ verbose: bool = False,
108
109
  ) -> "_Sandbox":
109
110
  """mdmd:hidden"""
110
111
 
@@ -205,6 +206,7 @@ class _Sandbox(_Object, type_prefix="sb"):
205
206
  network_access=network_access,
206
207
  proxy_id=(proxy.object_id if proxy else None),
207
208
  enable_snapshot=enable_snapshot,
209
+ verbose=verbose,
208
210
  )
209
211
 
210
212
  # Note - `resolver.app_id` will be `None` for app-less sandboxes
@@ -253,6 +255,8 @@ class _Sandbox(_Object, type_prefix="sb"):
253
255
  unencrypted_ports: Sequence[int] = [],
254
256
  # Reference to a Modal Proxy to use in front of this Sandbox.
255
257
  proxy: Optional[_Proxy] = None,
258
+ # Enable verbose logging for sandbox operations.
259
+ verbose: bool = False,
256
260
  # Enable memory snapshots.
257
261
  _experimental_enable_snapshot: bool = False,
258
262
  _experimental_scheduler_placement: Optional[
@@ -298,6 +302,7 @@ class _Sandbox(_Object, type_prefix="sb"):
298
302
  _experimental_enable_snapshot=_experimental_enable_snapshot,
299
303
  _experimental_scheduler_placement=_experimental_scheduler_placement,
300
304
  client=client,
305
+ verbose=verbose,
301
306
  )
302
307
 
303
308
  @staticmethod
@@ -342,6 +347,7 @@ class _Sandbox(_Object, type_prefix="sb"):
342
347
  SchedulerPlacement
343
348
  ] = None, # Experimental controls over fine-grained scheduling (alpha).
344
349
  client: Optional[_Client] = None,
350
+ verbose: bool = False,
345
351
  ):
346
352
  # This method exposes some internal arguments (currently `mounts`) which are not in the public API
347
353
  # `mounts` is currently only used by modal shell (cli) to provide a function's mounts to the
@@ -376,6 +382,7 @@ class _Sandbox(_Object, type_prefix="sb"):
376
382
  proxy=proxy,
377
383
  _experimental_scheduler_placement=_experimental_scheduler_placement,
378
384
  enable_snapshot=_experimental_enable_snapshot,
385
+ verbose=verbose,
379
386
  )
380
387
  obj._enable_snapshot = _experimental_enable_snapshot
381
388
 
@@ -63,6 +63,7 @@ class _Sandbox(modal._object._Object):
63
63
  proxy: typing.Optional[modal.proxy._Proxy] = None,
64
64
  _experimental_scheduler_placement: typing.Optional[modal.scheduler_placement.SchedulerPlacement] = None,
65
65
  enable_snapshot: bool = False,
66
+ verbose: bool = False,
66
67
  ) -> _Sandbox: ...
67
68
  @staticmethod
68
69
  async def create(
@@ -90,6 +91,7 @@ class _Sandbox(modal._object._Object):
90
91
  h2_ports: collections.abc.Sequence[int] = [],
91
92
  unencrypted_ports: collections.abc.Sequence[int] = [],
92
93
  proxy: typing.Optional[modal.proxy._Proxy] = None,
94
+ verbose: bool = False,
93
95
  _experimental_enable_snapshot: bool = False,
94
96
  _experimental_scheduler_placement: typing.Optional[modal.scheduler_placement.SchedulerPlacement] = None,
95
97
  client: typing.Optional[modal.client._Client] = None,
@@ -124,6 +126,7 @@ class _Sandbox(modal._object._Object):
124
126
  _experimental_enable_snapshot: bool = False,
125
127
  _experimental_scheduler_placement: typing.Optional[modal.scheduler_placement.SchedulerPlacement] = None,
126
128
  client: typing.Optional[modal.client._Client] = None,
129
+ verbose: bool = False,
127
130
  ): ...
128
131
  def _hydrate_metadata(self, handle_metadata: typing.Optional[google.protobuf.message.Message]): ...
129
132
  @staticmethod
@@ -236,6 +239,7 @@ class Sandbox(modal.object.Object):
236
239
  proxy: typing.Optional[modal.proxy.Proxy] = None,
237
240
  _experimental_scheduler_placement: typing.Optional[modal.scheduler_placement.SchedulerPlacement] = None,
238
241
  enable_snapshot: bool = False,
242
+ verbose: bool = False,
239
243
  ) -> Sandbox: ...
240
244
 
241
245
  class __create_spec(typing_extensions.Protocol):
@@ -268,6 +272,7 @@ class Sandbox(modal.object.Object):
268
272
  h2_ports: collections.abc.Sequence[int] = [],
269
273
  unencrypted_ports: collections.abc.Sequence[int] = [],
270
274
  proxy: typing.Optional[modal.proxy.Proxy] = None,
275
+ verbose: bool = False,
271
276
  _experimental_enable_snapshot: bool = False,
272
277
  _experimental_scheduler_placement: typing.Optional[modal.scheduler_placement.SchedulerPlacement] = None,
273
278
  client: typing.Optional[modal.client.Client] = None,
@@ -301,6 +306,7 @@ class Sandbox(modal.object.Object):
301
306
  h2_ports: collections.abc.Sequence[int] = [],
302
307
  unencrypted_ports: collections.abc.Sequence[int] = [],
303
308
  proxy: typing.Optional[modal.proxy.Proxy] = None,
309
+ verbose: bool = False,
304
310
  _experimental_enable_snapshot: bool = False,
305
311
  _experimental_scheduler_placement: typing.Optional[modal.scheduler_placement.SchedulerPlacement] = None,
306
312
  client: typing.Optional[modal.client.Client] = None,
@@ -342,6 +348,7 @@ class Sandbox(modal.object.Object):
342
348
  _experimental_enable_snapshot: bool = False,
343
349
  _experimental_scheduler_placement: typing.Optional[modal.scheduler_placement.SchedulerPlacement] = None,
344
350
  client: typing.Optional[modal.client.Client] = None,
351
+ verbose: bool = False,
345
352
  ): ...
346
353
  async def aio(
347
354
  self,
@@ -376,6 +383,7 @@ class Sandbox(modal.object.Object):
376
383
  _experimental_enable_snapshot: bool = False,
377
384
  _experimental_scheduler_placement: typing.Optional[modal.scheduler_placement.SchedulerPlacement] = None,
378
385
  client: typing.Optional[modal.client.Client] = None,
386
+ verbose: bool = False,
379
387
  ): ...
380
388
 
381
389
  _create: ___create_spec
@@ -403,6 +403,10 @@ class _Volume(_Object, type_prefix="vo"):
403
403
  """
404
404
  Read a file from the modal.Volume.
405
405
 
406
+ Note - this function is primarily intended to be used outside of a Modal App.
407
+ For more information on downloading files from a Modal Volume, see
408
+ [the guide](/docs/guide/volumes).
409
+
406
410
  **Example:**
407
411
 
408
412
  ```python notest
@@ -443,6 +447,7 @@ class _Volume(_Object, type_prefix="vo"):
443
447
  Read volume file into file-like IO object.
444
448
  """
445
449
  if progress_cb is None:
450
+
446
451
  def progress_cb(*_, **__):
447
452
  pass
448
453
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.0.4.dev4
3
+ Version: 1.0.4.dev7
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.0
22
22
  Requires-Dist: grpclib==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.9.13
25
+ Requires-Dist: synchronicity~=0.9.14
26
26
  Requires-Dist: toml
27
27
  Requires-Dist: typer>=0.9
28
28
  Requires-Dist: types-certifi
@@ -4,7 +4,7 @@ click~=8.1.0
4
4
  grpclib==0.4.7
5
5
  protobuf!=4.24.0,<7.0,>=3.19
6
6
  rich>=12.0.0
7
- synchronicity~=0.9.13
7
+ synchronicity~=0.9.14
8
8
  toml
9
9
  typer>=0.9
10
10
  types-certifi
@@ -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.0.4.dev4"
4
+ __version__ = "1.0.4.dev7"
@@ -20,7 +20,7 @@ dependencies = [
20
20
  "grpclib==0.4.7",
21
21
  "protobuf>=3.19,<7.0,!=4.24.0",
22
22
  "rich>=12.0.0",
23
- "synchronicity~=0.9.13",
23
+ "synchronicity~=0.9.14",
24
24
  "toml",
25
25
  "typer>=0.9",
26
26
  "types-certifi",
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes