modal 1.0.6.dev46__tar.gz → 1.0.6.dev47__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.0.6.dev46 → modal-1.0.6.dev47}/PKG-INFO +1 -1
  2. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/client.pyi +2 -2
  3. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/container_process.py +2 -0
  4. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/io_streams.py +19 -3
  5. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/io_streams.pyi +7 -1
  6. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/sandbox.py +2 -1
  7. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal.egg-info/PKG-INFO +1 -1
  8. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal_version/__init__.py +1 -1
  9. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/LICENSE +0 -0
  10. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/README.md +0 -0
  11. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/__init__.py +0 -0
  12. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/__main__.py +0 -0
  13. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/_clustered_functions.py +0 -0
  14. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/_clustered_functions.pyi +0 -0
  15. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/_container_entrypoint.py +0 -0
  16. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/_functions.py +0 -0
  17. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/_ipython.py +0 -0
  18. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/_location.py +0 -0
  19. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/_object.py +0 -0
  20. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/_output.py +0 -0
  21. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/_partial_function.py +0 -0
  22. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/_pty.py +0 -0
  23. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/_resolver.py +0 -0
  24. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/_resources.py +0 -0
  25. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/_runtime/__init__.py +0 -0
  26. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/_runtime/asgi.py +0 -0
  27. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/_runtime/container_io_manager.py +0 -0
  28. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/_runtime/container_io_manager.pyi +0 -0
  29. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/_runtime/execution_context.py +0 -0
  30. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/_runtime/execution_context.pyi +0 -0
  31. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/_runtime/gpu_memory_snapshot.py +0 -0
  32. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/_runtime/telemetry.py +0 -0
  33. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/_runtime/user_code_imports.py +0 -0
  34. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/_serialization.py +0 -0
  35. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/_traceback.py +0 -0
  36. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/_tunnel.py +0 -0
  37. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/_tunnel.pyi +0 -0
  38. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/_type_manager.py +0 -0
  39. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/_utils/__init__.py +0 -0
  40. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/_utils/app_utils.py +0 -0
  41. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/_utils/async_utils.py +0 -0
  42. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/_utils/auth_token_manager.py +0 -0
  43. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/_utils/blob_utils.py +0 -0
  44. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/_utils/bytes_io_segment_payload.py +0 -0
  45. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/_utils/deprecation.py +0 -0
  46. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/_utils/docker_utils.py +0 -0
  47. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/_utils/function_utils.py +0 -0
  48. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/_utils/git_utils.py +0 -0
  49. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/_utils/grpc_testing.py +0 -0
  50. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/_utils/grpc_utils.py +0 -0
  51. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/_utils/hash_utils.py +0 -0
  52. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/_utils/http_utils.py +0 -0
  53. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/_utils/jwt_utils.py +0 -0
  54. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/_utils/logger.py +0 -0
  55. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/_utils/mount_utils.py +0 -0
  56. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/_utils/name_utils.py +0 -0
  57. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/_utils/package_utils.py +0 -0
  58. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/_utils/pattern_utils.py +0 -0
  59. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/_utils/rand_pb_testing.py +0 -0
  60. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/_utils/shell_utils.py +0 -0
  61. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/_utils/time_utils.py +0 -0
  62. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/_vendor/__init__.py +0 -0
  63. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/_vendor/a2wsgi_wsgi.py +0 -0
  64. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/_vendor/cloudpickle.py +0 -0
  65. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/_vendor/tblib.py +0 -0
  66. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/_watcher.py +0 -0
  67. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/app.py +0 -0
  68. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/app.pyi +0 -0
  69. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/call_graph.py +0 -0
  70. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/cli/__init__.py +0 -0
  71. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/cli/_download.py +0 -0
  72. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/cli/_traceback.py +0 -0
  73. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/cli/app.py +0 -0
  74. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/cli/cluster.py +0 -0
  75. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/cli/config.py +0 -0
  76. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/cli/container.py +0 -0
  77. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/cli/dict.py +0 -0
  78. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/cli/entry_point.py +0 -0
  79. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/cli/environment.py +0 -0
  80. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/cli/import_refs.py +0 -0
  81. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/cli/launch.py +0 -0
  82. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/cli/network_file_system.py +0 -0
  83. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/cli/profile.py +0 -0
  84. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/cli/programs/__init__.py +0 -0
  85. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/cli/programs/run_jupyter.py +0 -0
  86. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/cli/programs/vscode.py +0 -0
  87. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/cli/queues.py +0 -0
  88. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/cli/run.py +0 -0
  89. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/cli/secret.py +0 -0
  90. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/cli/token.py +0 -0
  91. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/cli/utils.py +0 -0
  92. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/cli/volume.py +0 -0
  93. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/client.py +0 -0
  94. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/cloud_bucket_mount.py +0 -0
  95. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/cloud_bucket_mount.pyi +0 -0
  96. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/cls.py +0 -0
  97. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/cls.pyi +0 -0
  98. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/config.py +0 -0
  99. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/container_process.pyi +0 -0
  100. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/dict.py +0 -0
  101. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/dict.pyi +0 -0
  102. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/environments.py +0 -0
  103. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/environments.pyi +0 -0
  104. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/exception.py +0 -0
  105. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/experimental/__init__.py +0 -0
  106. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/experimental/flash.py +0 -0
  107. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/experimental/flash.pyi +0 -0
  108. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/experimental/ipython.py +0 -0
  109. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/file_io.py +0 -0
  110. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/file_io.pyi +0 -0
  111. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/file_pattern_matcher.py +0 -0
  112. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/functions.py +0 -0
  113. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/functions.pyi +0 -0
  114. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/gpu.py +0 -0
  115. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/image.py +0 -0
  116. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/image.pyi +0 -0
  117. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/mount.py +0 -0
  118. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/mount.pyi +0 -0
  119. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/network_file_system.py +0 -0
  120. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/network_file_system.pyi +0 -0
  121. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/object.py +0 -0
  122. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/object.pyi +0 -0
  123. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/output.py +0 -0
  124. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/parallel_map.py +0 -0
  125. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/parallel_map.pyi +0 -0
  126. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/partial_function.py +0 -0
  127. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/partial_function.pyi +0 -0
  128. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/proxy.py +0 -0
  129. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/proxy.pyi +0 -0
  130. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/py.typed +0 -0
  131. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/queue.py +0 -0
  132. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/queue.pyi +0 -0
  133. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/requirements/2023.12.312.txt +0 -0
  134. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/requirements/2023.12.txt +0 -0
  135. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/requirements/2024.04.txt +0 -0
  136. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/requirements/2024.10.txt +0 -0
  137. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/requirements/2025.06.txt +0 -0
  138. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/requirements/PREVIEW.txt +0 -0
  139. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/requirements/README.md +0 -0
  140. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/requirements/base-images.json +0 -0
  141. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/retries.py +0 -0
  142. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/runner.py +0 -0
  143. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/runner.pyi +0 -0
  144. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/running_app.py +0 -0
  145. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/sandbox.pyi +0 -0
  146. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/schedule.py +0 -0
  147. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/scheduler_placement.py +0 -0
  148. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/secret.py +0 -0
  149. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/secret.pyi +0 -0
  150. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/serving.py +0 -0
  151. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/serving.pyi +0 -0
  152. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/snapshot.py +0 -0
  153. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/snapshot.pyi +0 -0
  154. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/stream_type.py +0 -0
  155. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/token_flow.py +0 -0
  156. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/token_flow.pyi +0 -0
  157. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/volume.py +0 -0
  158. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal/volume.pyi +0 -0
  159. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal.egg-info/SOURCES.txt +0 -0
  160. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal.egg-info/dependency_links.txt +0 -0
  161. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal.egg-info/entry_points.txt +0 -0
  162. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal.egg-info/requires.txt +0 -0
  163. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal.egg-info/top_level.txt +0 -0
  164. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal_docs/__init__.py +0 -0
  165. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal_docs/gen_cli_docs.py +0 -0
  166. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal_docs/gen_reference_docs.py +0 -0
  167. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal_docs/mdmd/__init__.py +0 -0
  168. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal_docs/mdmd/mdmd.py +0 -0
  169. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal_docs/mdmd/signatures.py +0 -0
  170. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal_proto/__init__.py +0 -0
  171. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal_proto/api.proto +0 -0
  172. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal_proto/api_grpc.py +0 -0
  173. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal_proto/api_pb2.py +0 -0
  174. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal_proto/api_pb2.pyi +0 -0
  175. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal_proto/api_pb2_grpc.py +0 -0
  176. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal_proto/api_pb2_grpc.pyi +0 -0
  177. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal_proto/modal_api_grpc.py +0 -0
  178. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal_proto/modal_options_grpc.py +0 -0
  179. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal_proto/options.proto +0 -0
  180. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal_proto/options_grpc.py +0 -0
  181. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal_proto/options_pb2.py +0 -0
  182. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal_proto/options_pb2.pyi +0 -0
  183. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal_proto/options_pb2_grpc.py +0 -0
  184. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal_proto/options_pb2_grpc.pyi +0 -0
  185. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal_proto/py.typed +0 -0
  186. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/modal_version/__main__.py +0 -0
  187. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/pyproject.toml +0 -0
  188. {modal-1.0.6.dev46 → modal-1.0.6.dev47}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.0.6.dev46
3
+ Version: 1.0.6.dev47
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License: Apache-2.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.0.6.dev46",
36
+ version: str = "1.0.6.dev47",
37
37
  ):
38
38
  """mdmd:hidden
39
39
  The Modal client object is not intended to be instantiated directly by users.
@@ -163,7 +163,7 @@ class Client:
163
163
  server_url: str,
164
164
  client_type: int,
165
165
  credentials: typing.Optional[tuple[str, str]],
166
- version: str = "1.0.6.dev46",
166
+ version: str = "1.0.6.dev47",
167
167
  ):
168
168
  """mdmd:hidden
169
169
  The Modal client object is not intended to be instantiated directly by users.
@@ -50,6 +50,7 @@ class _ContainerProcess(Generic[T]):
50
50
  stream_type=stdout,
51
51
  text=text,
52
52
  by_line=by_line,
53
+ deadline=exec_deadline,
53
54
  )
54
55
  self._stderr = _StreamReader[T](
55
56
  api_pb2.FILE_DESCRIPTOR_STDERR,
@@ -59,6 +60,7 @@ class _ContainerProcess(Generic[T]):
59
60
  stream_type=stderr,
60
61
  text=text,
61
62
  by_line=by_line,
63
+ deadline=exec_deadline,
62
64
  )
63
65
  self._stdin = _StreamWriter(process_id, "container_process", self._client)
64
66
 
@@ -1,5 +1,6 @@
1
1
  # Copyright Modal Labs 2022
2
2
  import asyncio
3
+ import time
3
4
  from collections.abc import AsyncGenerator, AsyncIterator
4
5
  from typing import (
5
6
  TYPE_CHECKING,
@@ -50,6 +51,7 @@ async def _container_process_logs_iterator(
50
51
  file_descriptor: "api_pb2.FileDescriptor.ValueType",
51
52
  client: _Client,
52
53
  last_index: int,
54
+ deadline: Optional[float] = None,
53
55
  ) -> AsyncGenerator[tuple[Optional[bytes], int], None]:
54
56
  req = api_pb2.ContainerExecGetOutputRequest(
55
57
  exec_id=process_id,
@@ -58,7 +60,18 @@ async def _container_process_logs_iterator(
58
60
  get_raw_bytes=True,
59
61
  last_batch_index=last_index,
60
62
  )
61
- async for batch in client.stub.ContainerExecGetOutput.unary_stream(req):
63
+
64
+ stream = client.stub.ContainerExecGetOutput.unary_stream(req)
65
+ while True:
66
+ # Check deadline before attempting to receive the next batch
67
+ try:
68
+ remaining = (deadline - time.monotonic()) if deadline else None
69
+ batch = await asyncio.wait_for(stream.__anext__(), timeout=remaining)
70
+ except asyncio.TimeoutError:
71
+ yield None, -1
72
+ break
73
+ except StopAsyncIteration:
74
+ break
62
75
  if batch.HasField("exit_code"):
63
76
  yield None, batch.batch_index
64
77
  break
@@ -102,6 +115,7 @@ class _StreamReader(Generic[T]):
102
115
  stream_type: StreamType = StreamType.PIPE,
103
116
  text: bool = True,
104
117
  by_line: bool = False,
118
+ deadline: Optional[float] = None,
105
119
  ) -> None:
106
120
  """mdmd:hidden"""
107
121
  self._file_descriptor = file_descriptor
@@ -111,6 +125,7 @@ class _StreamReader(Generic[T]):
111
125
  self._stream = None
112
126
  self._last_entry_id: str = ""
113
127
  self._line_buffer = b""
128
+ self._deadline = deadline
114
129
 
115
130
  # Sandbox logs are streamed to the client as strings, so StreamReaders reading
116
131
  # them must have text mode enabled.
@@ -187,11 +202,12 @@ class _StreamReader(Generic[T]):
187
202
  retries_remaining = 10
188
203
  last_index = 0
189
204
  while not completed:
205
+ if self._deadline and time.monotonic() >= self._deadline:
206
+ break
190
207
  try:
191
208
  iterator = _container_process_logs_iterator(
192
- self._object_id, self._file_descriptor, self._client, last_index
209
+ self._object_id, self._file_descriptor, self._client, last_index, self._deadline
193
210
  )
194
-
195
211
  async for message, batch_index in iterator:
196
212
  if self._stream_type == StreamType.STDOUT and message:
197
213
  print(message.decode("utf-8"), end="")
@@ -8,7 +8,11 @@ def _sandbox_logs_iterator(
8
8
  sandbox_id: str, file_descriptor: int, last_entry_id: str, client: modal.client._Client
9
9
  ) -> collections.abc.AsyncGenerator[tuple[typing.Optional[bytes], str], None]: ...
10
10
  def _container_process_logs_iterator(
11
- process_id: str, file_descriptor: int, client: modal.client._Client, last_index: int
11
+ process_id: str,
12
+ file_descriptor: int,
13
+ client: modal.client._Client,
14
+ last_index: int,
15
+ deadline: typing.Optional[float] = None,
12
16
  ) -> collections.abc.AsyncGenerator[tuple[typing.Optional[bytes], int], None]: ...
13
17
 
14
18
  T = typing.TypeVar("T")
@@ -46,6 +50,7 @@ class _StreamReader(typing.Generic[T]):
46
50
  stream_type: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
47
51
  text: bool = True,
48
52
  by_line: bool = False,
53
+ deadline: typing.Optional[float] = None,
49
54
  ) -> None:
50
55
  """mdmd:hidden"""
51
56
  ...
@@ -211,6 +216,7 @@ class StreamReader(typing.Generic[T]):
211
216
  stream_type: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
212
217
  text: bool = True,
213
218
  by_line: bool = False,
219
+ deadline: typing.Optional[float] = None,
214
220
  ) -> None:
215
221
  """mdmd:hidden"""
216
222
  ...
@@ -50,10 +50,11 @@ _default_image: _Image = _Image.debian_slim()
50
50
  # e.g. 'runsc exec ...'. So we use 2**16 as the limit.
51
51
  ARG_MAX_BYTES = 2**16
52
52
 
53
-
54
53
  # This buffer extends the user-supplied timeout on ContainerExec-related RPCs. This was introduced to
55
54
  # give any in-flight status codes/IO data more time to reach the client before the stream is closed.
56
55
  CONTAINER_EXEC_TIMEOUT_BUFFER = 5
56
+
57
+
57
58
  if TYPE_CHECKING:
58
59
  import modal.app
59
60
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.0.6.dev46
3
+ Version: 1.0.6.dev47
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.0.6.dev46"
4
+ __version__ = "1.0.6.dev47"
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