modal 1.2.3.dev14__tar.gz → 1.2.3.dev16__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 (200) hide show
  1. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/PKG-INFO +1 -1
  2. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_utils/grpc_utils.py +26 -16
  3. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/client.pyi +2 -2
  4. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/config.py +5 -8
  5. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/functions.pyi +6 -6
  6. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal.egg-info/PKG-INFO +1 -1
  7. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal_version/__init__.py +1 -1
  8. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/LICENSE +0 -0
  9. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/README.md +0 -0
  10. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/__init__.py +0 -0
  11. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/__main__.py +0 -0
  12. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_billing.py +0 -0
  13. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_clustered_functions.py +0 -0
  14. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_clustered_functions.pyi +0 -0
  15. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_container_entrypoint.py +0 -0
  16. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_functions.py +0 -0
  17. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_grpc_client.py +0 -0
  18. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_ipython.py +0 -0
  19. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_load_context.py +0 -0
  20. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_location.py +0 -0
  21. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_object.py +0 -0
  22. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_output.py +0 -0
  23. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_partial_function.py +0 -0
  24. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_pty.py +0 -0
  25. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_resolver.py +0 -0
  26. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_resources.py +0 -0
  27. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_runtime/__init__.py +0 -0
  28. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_runtime/asgi.py +0 -0
  29. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_runtime/container_io_manager.py +0 -0
  30. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_runtime/container_io_manager.pyi +0 -0
  31. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_runtime/execution_context.py +0 -0
  32. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_runtime/execution_context.pyi +0 -0
  33. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_runtime/gpu_memory_snapshot.py +0 -0
  34. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_runtime/telemetry.py +0 -0
  35. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_runtime/user_code_imports.py +0 -0
  36. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_serialization.py +0 -0
  37. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_traceback.py +0 -0
  38. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_tunnel.py +0 -0
  39. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_tunnel.pyi +0 -0
  40. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_type_manager.py +0 -0
  41. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_utils/__init__.py +0 -0
  42. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_utils/app_utils.py +0 -0
  43. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_utils/async_utils.py +0 -0
  44. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_utils/auth_token_manager.py +0 -0
  45. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_utils/blob_utils.py +0 -0
  46. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_utils/bytes_io_segment_payload.py +0 -0
  47. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_utils/deprecation.py +0 -0
  48. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_utils/docker_utils.py +0 -0
  49. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_utils/function_utils.py +0 -0
  50. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_utils/git_utils.py +0 -0
  51. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_utils/grpc_testing.py +0 -0
  52. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_utils/hash_utils.py +0 -0
  53. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_utils/http_utils.py +0 -0
  54. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_utils/jwt_utils.py +0 -0
  55. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_utils/logger.py +0 -0
  56. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_utils/mount_utils.py +0 -0
  57. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_utils/name_utils.py +0 -0
  58. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_utils/package_utils.py +0 -0
  59. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_utils/pattern_utils.py +0 -0
  60. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_utils/rand_pb_testing.py +0 -0
  61. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_utils/shell_utils.py +0 -0
  62. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_utils/task_command_router_client.py +0 -0
  63. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_utils/time_utils.py +0 -0
  64. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_vendor/__init__.py +0 -0
  65. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_vendor/a2wsgi_wsgi.py +0 -0
  66. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_vendor/cloudpickle.py +0 -0
  67. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_vendor/tblib.py +0 -0
  68. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/_watcher.py +0 -0
  69. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/app.py +0 -0
  70. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/app.pyi +0 -0
  71. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/billing.py +0 -0
  72. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/builder/2023.12.312.txt +0 -0
  73. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/builder/2023.12.txt +0 -0
  74. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/builder/2024.04.txt +0 -0
  75. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/builder/2024.10.txt +0 -0
  76. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/builder/2025.06.txt +0 -0
  77. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/builder/PREVIEW.txt +0 -0
  78. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/builder/README.md +0 -0
  79. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/builder/base-images.json +0 -0
  80. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/call_graph.py +0 -0
  81. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/cli/__init__.py +0 -0
  82. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/cli/_download.py +0 -0
  83. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/cli/_traceback.py +0 -0
  84. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/cli/app.py +0 -0
  85. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/cli/cluster.py +0 -0
  86. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/cli/config.py +0 -0
  87. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/cli/container.py +0 -0
  88. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/cli/dict.py +0 -0
  89. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/cli/entry_point.py +0 -0
  90. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/cli/environment.py +0 -0
  91. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/cli/import_refs.py +0 -0
  92. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/cli/launch.py +0 -0
  93. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/cli/network_file_system.py +0 -0
  94. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/cli/profile.py +0 -0
  95. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/cli/programs/__init__.py +0 -0
  96. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/cli/programs/launch_instance_ssh.py +0 -0
  97. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/cli/programs/run_jupyter.py +0 -0
  98. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/cli/programs/run_marimo.py +0 -0
  99. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/cli/programs/vscode.py +0 -0
  100. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/cli/queues.py +0 -0
  101. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/cli/run.py +0 -0
  102. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/cli/secret.py +0 -0
  103. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/cli/token.py +0 -0
  104. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/cli/utils.py +0 -0
  105. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/cli/volume.py +0 -0
  106. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/client.py +0 -0
  107. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/cloud_bucket_mount.py +0 -0
  108. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/cloud_bucket_mount.pyi +0 -0
  109. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/cls.py +0 -0
  110. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/cls.pyi +0 -0
  111. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/container_process.py +0 -0
  112. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/container_process.pyi +0 -0
  113. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/dict.py +0 -0
  114. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/dict.pyi +0 -0
  115. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/environments.py +0 -0
  116. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/environments.pyi +0 -0
  117. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/exception.py +0 -0
  118. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/experimental/__init__.py +0 -0
  119. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/experimental/flash.py +0 -0
  120. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/experimental/flash.pyi +0 -0
  121. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/experimental/ipython.py +0 -0
  122. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/file_io.py +0 -0
  123. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/file_io.pyi +0 -0
  124. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/file_pattern_matcher.py +0 -0
  125. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/functions.py +0 -0
  126. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/gpu.py +0 -0
  127. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/image.py +0 -0
  128. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/image.pyi +0 -0
  129. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/io_streams.py +0 -0
  130. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/io_streams.pyi +0 -0
  131. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/mount.py +0 -0
  132. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/mount.pyi +0 -0
  133. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/network_file_system.py +0 -0
  134. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/network_file_system.pyi +0 -0
  135. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/object.py +0 -0
  136. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/object.pyi +0 -0
  137. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/output.py +0 -0
  138. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/parallel_map.py +0 -0
  139. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/parallel_map.pyi +0 -0
  140. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/partial_function.py +0 -0
  141. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/partial_function.pyi +0 -0
  142. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/proxy.py +0 -0
  143. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/proxy.pyi +0 -0
  144. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/py.typed +0 -0
  145. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/queue.py +0 -0
  146. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/queue.pyi +0 -0
  147. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/retries.py +0 -0
  148. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/runner.py +0 -0
  149. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/runner.pyi +0 -0
  150. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/running_app.py +0 -0
  151. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/sandbox.py +0 -0
  152. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/sandbox.pyi +0 -0
  153. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/schedule.py +0 -0
  154. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/scheduler_placement.py +0 -0
  155. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/secret.py +0 -0
  156. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/secret.pyi +0 -0
  157. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/serving.py +0 -0
  158. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/serving.pyi +0 -0
  159. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/snapshot.py +0 -0
  160. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/snapshot.pyi +0 -0
  161. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/stream_type.py +0 -0
  162. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/token_flow.py +0 -0
  163. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/token_flow.pyi +0 -0
  164. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/volume.py +0 -0
  165. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal/volume.pyi +0 -0
  166. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal.egg-info/SOURCES.txt +0 -0
  167. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal.egg-info/dependency_links.txt +0 -0
  168. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal.egg-info/entry_points.txt +0 -0
  169. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal.egg-info/requires.txt +0 -0
  170. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal.egg-info/top_level.txt +0 -0
  171. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal_docs/__init__.py +0 -0
  172. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal_docs/gen_cli_docs.py +0 -0
  173. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal_docs/gen_reference_docs.py +0 -0
  174. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal_docs/mdmd/__init__.py +0 -0
  175. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal_docs/mdmd/mdmd.py +0 -0
  176. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal_docs/mdmd/signatures.py +0 -0
  177. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal_proto/__init__.py +0 -0
  178. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal_proto/api.proto +0 -0
  179. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal_proto/api_grpc.py +0 -0
  180. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal_proto/api_pb2.py +0 -0
  181. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal_proto/api_pb2.pyi +0 -0
  182. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal_proto/api_pb2_grpc.py +0 -0
  183. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal_proto/api_pb2_grpc.pyi +0 -0
  184. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal_proto/modal_api_grpc.py +0 -0
  185. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal_proto/py.typed +0 -0
  186. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal_proto/sandbox_router.proto +0 -0
  187. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal_proto/sandbox_router_grpc.py +0 -0
  188. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal_proto/sandbox_router_pb2.py +0 -0
  189. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal_proto/sandbox_router_pb2.pyi +0 -0
  190. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal_proto/sandbox_router_pb2_grpc.py +0 -0
  191. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal_proto/sandbox_router_pb2_grpc.pyi +0 -0
  192. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal_proto/task_command_router.proto +0 -0
  193. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal_proto/task_command_router_grpc.py +0 -0
  194. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal_proto/task_command_router_pb2.py +0 -0
  195. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal_proto/task_command_router_pb2.pyi +0 -0
  196. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal_proto/task_command_router_pb2_grpc.py +0 -0
  197. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal_proto/task_command_router_pb2_grpc.pyi +0 -0
  198. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/modal_version/__main__.py +0 -0
  199. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/pyproject.toml +0 -0
  200. {modal-1.2.3.dev14 → modal-1.2.3.dev16}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.2.3.dev14
3
+ Version: 1.2.3.dev16
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License: Apache-2.0
@@ -271,15 +271,13 @@ def process_exception_before_retry(
271
271
  fn_name: str,
272
272
  n_retries: int,
273
273
  delay: float,
274
- total_deadline: Optional[float],
275
274
  idempotency_key: str,
276
275
  ):
277
276
  """Process exception before retry, used by `_retry_transient_errors`."""
278
277
  with suppress_tb_frames(1):
279
278
  if final_attempt:
280
279
  logger.debug(
281
- f"Final attempt failed with {repr(exc)} {n_retries=} {delay=} "
282
- f"{total_deadline=} for {fn_name} ({idempotency_key[:8]})"
280
+ f"Final attempt failed with {repr(exc)} {n_retries=} {delay=} for {fn_name} ({idempotency_key[:8]})"
283
281
  )
284
282
  if isinstance(exc, OSError):
285
283
  raise ConnectionError(str(exc))
@@ -292,6 +290,8 @@ def process_exception_before_retry(
292
290
  # StreamTerminatedError are not properly raised in grpclib<=0.4.7
293
291
  # fixed in https://github.com/vmagamedov/grpclib/issues/185
294
292
  # TODO: update to newer version (>=0.4.8) once stable
293
+ # Also be sure to remove the AttributeError from the set of exceptions
294
+ # we handle in the retry logic once we drop this check!
295
295
  raise exc
296
296
 
297
297
  logger.debug(f"Retryable failure {repr(exc)} {n_retries=} {delay=} for {fn_name} ({idempotency_key[:8]})")
@@ -356,26 +356,38 @@ async def _retry_transient_errors(
356
356
  timeout = min(timeouts) # In case the function provided both types of timeouts
357
357
  else:
358
358
  timeout = None
359
+
359
360
  try:
360
361
  with suppress_tb_frames(1):
361
362
  return await fn_callable(req, metadata=attempt_metadata, timeout=timeout)
362
363
  except (StreamTerminatedError, GRPCError, OSError, asyncio.TimeoutError, AttributeError) as exc:
364
+ # Note that we only catch AttributeError to handle a specific case that works around a bug
365
+ # in grpclib<=0.4.7. See above (search for `write_appdata`).
366
+
363
367
  # Server side instruction for retries
364
- if isinstance(exc, GRPCError) and (server_retry_policy := get_server_retry_policy(exc)):
368
+ max_throttle_wait: Optional[int] = config.get("max_throttle_wait")
369
+ if (
370
+ max_throttle_wait != 0
371
+ and isinstance(exc, GRPCError)
372
+ and (server_retry_policy := get_server_retry_policy(exc))
373
+ ):
365
374
  server_delay = server_retry_policy.retry_after_secs
366
375
 
367
- # When `total_deadline` is not defined and server gives instruction for retries, then use
368
- # `max_throttle_wait`.
369
- if total_deadline is None and (max_throttle_wait := config.get("max_throttle_wait")):
370
- total_deadline = t0 + max_throttle_wait
376
+ now = time.time()
371
377
 
372
- final_attempt = (
373
- total_deadline is not None
374
- and time.time() + server_delay + retry.attempt_timeout_floor >= total_deadline
378
+ # We check if the timeout will be reached **after** the sleep, so we can raise an error early
379
+ # without needing to actually sleep.
380
+ total_timeout_will_be_reached = (
381
+ retry.total_timeout is not None and (now + server_delay - t0) >= retry.total_timeout
382
+ )
383
+ max_throttle_will_be_reached = (
384
+ max_throttle_wait is not None and (now + server_delay - t0) >= max_throttle_wait
375
385
  )
386
+ final_attempt = total_timeout_will_be_reached or max_throttle_will_be_reached
387
+
376
388
  with suppress_tb_frames(1):
377
389
  process_exception_before_retry(
378
- exc, final_attempt, fn.name, n_retries, server_delay, total_deadline, idempotency_key
390
+ exc, final_attempt, fn.name, n_retries, server_delay, idempotency_key
379
391
  )
380
392
 
381
393
  now = time.time()
@@ -384,7 +396,7 @@ async def _retry_transient_errors(
384
396
  ):
385
397
  last_server_retry_warning_time = now
386
398
  logger.warning(
387
- f"Warning: Received failure {exc.status}: {exc.message}. "
399
+ f"Warning: Received {exc.status} status: {exc.message}. "
388
400
  f"Will retry in {server_delay:0.2f} seconds."
389
401
  )
390
402
 
@@ -406,9 +418,7 @@ async def _retry_transient_errors(
406
418
  final_attempt = False
407
419
 
408
420
  with suppress_tb_frames(1):
409
- process_exception_before_retry(
410
- exc, final_attempt, fn.name, n_retries, delay, total_deadline, idempotency_key
411
- )
421
+ process_exception_before_retry(exc, final_attempt, fn.name, n_retries, delay, idempotency_key)
412
422
 
413
423
  n_retries += 1
414
424
 
@@ -32,7 +32,7 @@ class _Client:
32
32
  server_url: str,
33
33
  client_type: int,
34
34
  credentials: typing.Optional[tuple[str, str]],
35
- version: str = "1.2.3.dev14",
35
+ version: str = "1.2.3.dev16",
36
36
  ):
37
37
  """mdmd:hidden
38
38
  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.2.3.dev14",
166
+ version: str = "1.2.3.dev16",
167
167
  ):
168
168
  """mdmd:hidden
169
169
  The Modal client object is not intended to be instantiated directly by users.
@@ -51,6 +51,10 @@ Other possible configuration options are:
51
51
  Defaults to 10.
52
52
  Number of seconds to wait for logs to drain when closing the session,
53
53
  before giving up.
54
+ * `max_throttle_wait` (in the .toml file) / `MODAL_MAX_THROTTLE_WAIT` (as an env var).
55
+ Defaults to None (no limit).
56
+ Maximum number of seconds to wait when requests are being throttled (i.e., due
57
+ to rate limiting or other cases that can normally be resolved through backoff).
54
58
  * `force_build` (in the .toml file) / `MODAL_FORCE_BUILD` (as an env var).
55
59
  Defaults to False.
56
60
  When set, ignores the Image cache and builds all Image layers. Note that this
@@ -217,13 +221,6 @@ def _enforce_suffix_rules(x: str) -> str:
217
221
  return x
218
222
 
219
223
 
220
- def _int_or_none(x: str) -> Optional[int]:
221
- if not x:
222
- return None
223
- x_int = int(x)
224
- return x_int if x_int > 0 else None
225
-
226
-
227
224
  class _Setting(typing.NamedTuple):
228
225
  default: typing.Any = None
229
226
  transform: typing.Callable[[str], typing.Any] = lambda x: x # noqa: E731
@@ -265,7 +262,7 @@ _SETTINGS = {
265
262
  transform=lambda s: _check_value(["pickle", "cbor"])(s.lower()),
266
263
  ),
267
264
  "dev_suffix": _Setting("", transform=_enforce_suffix_rules),
268
- "max_throttle_wait": _Setting(None, transform=_int_or_none),
265
+ "max_throttle_wait": _Setting(None, transform=lambda x: int(x) if x else None),
269
266
  }
270
267
 
271
268
 
@@ -408,7 +408,7 @@ class Function(
408
408
 
409
409
  _call_generator: ___call_generator_spec[typing_extensions.Self]
410
410
 
411
- class __remote_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER, SUPERSELF]):
411
+ class __remote_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER, SUPERSELF]):
412
412
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> ReturnType_INNER:
413
413
  """Calls the function remotely, executing it with the given arguments and returning the execution's result."""
414
414
  ...
@@ -417,7 +417,7 @@ class Function(
417
417
  """Calls the function remotely, executing it with the given arguments and returning the execution's result."""
418
418
  ...
419
419
 
420
- remote: __remote_spec[modal._functions.ReturnType, modal._functions.P, typing_extensions.Self]
420
+ remote: __remote_spec[modal._functions.P, modal._functions.ReturnType, typing_extensions.Self]
421
421
 
422
422
  class __remote_gen_spec(typing_extensions.Protocol[SUPERSELF]):
423
423
  def __call__(self, /, *args, **kwargs) -> typing.Generator[typing.Any, None, None]:
@@ -444,7 +444,7 @@ class Function(
444
444
  """
445
445
  ...
446
446
 
447
- class ___experimental_spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER, SUPERSELF]):
447
+ class ___experimental_spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER, SUPERSELF]):
448
448
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
449
449
  """[Experimental] Calls the function with the given arguments, without waiting for the results.
450
450
 
@@ -468,7 +468,7 @@ class Function(
468
468
  ...
469
469
 
470
470
  _experimental_spawn: ___experimental_spawn_spec[
471
- modal._functions.ReturnType, modal._functions.P, typing_extensions.Self
471
+ modal._functions.P, modal._functions.ReturnType, typing_extensions.Self
472
472
  ]
473
473
 
474
474
  class ___spawn_map_inner_spec(typing_extensions.Protocol[P_INNER, SUPERSELF]):
@@ -477,7 +477,7 @@ class Function(
477
477
 
478
478
  _spawn_map_inner: ___spawn_map_inner_spec[modal._functions.P, typing_extensions.Self]
479
479
 
480
- class __spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER, SUPERSELF]):
480
+ class __spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER, SUPERSELF]):
481
481
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
482
482
  """Calls the function with the given arguments, without waiting for the results.
483
483
 
@@ -498,7 +498,7 @@ class Function(
498
498
  """
499
499
  ...
500
500
 
501
- spawn: __spawn_spec[modal._functions.ReturnType, modal._functions.P, typing_extensions.Self]
501
+ spawn: __spawn_spec[modal._functions.P, modal._functions.ReturnType, typing_extensions.Self]
502
502
 
503
503
  def get_raw_f(self) -> collections.abc.Callable[..., typing.Any]:
504
504
  """Return the inner Python object wrapped by this Modal Function."""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.2.3.dev14
3
+ Version: 1.2.3.dev16
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.2.3.dev14"
4
+ __version__ = "1.2.3.dev16"
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