modal 1.2.3.dev9__tar.gz → 1.2.3.dev10__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.dev9 → modal-1.2.3.dev10}/PKG-INFO +1 -1
  2. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_utils/grpc_utils.py +57 -4
  3. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/client.pyi +2 -2
  4. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal.egg-info/PKG-INFO +1 -1
  5. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal_proto/api.proto +13 -0
  6. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal_proto/api_grpc.py +1 -0
  7. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal_proto/api_pb2.py +1032 -1021
  8. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal_proto/api_pb2.pyi +29 -0
  9. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal_version/__init__.py +1 -1
  10. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/LICENSE +0 -0
  11. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/README.md +0 -0
  12. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/__init__.py +0 -0
  13. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/__main__.py +0 -0
  14. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_billing.py +0 -0
  15. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_clustered_functions.py +0 -0
  16. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_clustered_functions.pyi +0 -0
  17. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_container_entrypoint.py +0 -0
  18. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_functions.py +0 -0
  19. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_grpc_client.py +0 -0
  20. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_ipython.py +0 -0
  21. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_load_context.py +0 -0
  22. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_location.py +0 -0
  23. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_object.py +0 -0
  24. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_output.py +0 -0
  25. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_partial_function.py +0 -0
  26. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_pty.py +0 -0
  27. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_resolver.py +0 -0
  28. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_resources.py +0 -0
  29. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_runtime/__init__.py +0 -0
  30. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_runtime/asgi.py +0 -0
  31. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_runtime/container_io_manager.py +0 -0
  32. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_runtime/container_io_manager.pyi +0 -0
  33. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_runtime/execution_context.py +0 -0
  34. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_runtime/execution_context.pyi +0 -0
  35. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_runtime/gpu_memory_snapshot.py +0 -0
  36. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_runtime/telemetry.py +0 -0
  37. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_runtime/user_code_imports.py +0 -0
  38. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_serialization.py +0 -0
  39. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_traceback.py +0 -0
  40. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_tunnel.py +0 -0
  41. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_tunnel.pyi +0 -0
  42. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_type_manager.py +0 -0
  43. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_utils/__init__.py +0 -0
  44. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_utils/app_utils.py +0 -0
  45. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_utils/async_utils.py +0 -0
  46. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_utils/auth_token_manager.py +0 -0
  47. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_utils/blob_utils.py +0 -0
  48. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_utils/bytes_io_segment_payload.py +0 -0
  49. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_utils/deprecation.py +0 -0
  50. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_utils/docker_utils.py +0 -0
  51. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_utils/function_utils.py +0 -0
  52. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_utils/git_utils.py +0 -0
  53. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_utils/grpc_testing.py +0 -0
  54. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_utils/hash_utils.py +0 -0
  55. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_utils/http_utils.py +0 -0
  56. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_utils/jwt_utils.py +0 -0
  57. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_utils/logger.py +0 -0
  58. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_utils/mount_utils.py +0 -0
  59. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_utils/name_utils.py +0 -0
  60. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_utils/package_utils.py +0 -0
  61. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_utils/pattern_utils.py +0 -0
  62. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_utils/rand_pb_testing.py +0 -0
  63. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_utils/shell_utils.py +0 -0
  64. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_utils/task_command_router_client.py +0 -0
  65. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_utils/time_utils.py +0 -0
  66. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_vendor/__init__.py +0 -0
  67. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_vendor/a2wsgi_wsgi.py +0 -0
  68. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_vendor/cloudpickle.py +0 -0
  69. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_vendor/tblib.py +0 -0
  70. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/_watcher.py +0 -0
  71. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/app.py +0 -0
  72. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/app.pyi +0 -0
  73. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/billing.py +0 -0
  74. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/builder/2023.12.312.txt +0 -0
  75. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/builder/2023.12.txt +0 -0
  76. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/builder/2024.04.txt +0 -0
  77. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/builder/2024.10.txt +0 -0
  78. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/builder/2025.06.txt +0 -0
  79. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/builder/PREVIEW.txt +0 -0
  80. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/builder/README.md +0 -0
  81. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/builder/base-images.json +0 -0
  82. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/call_graph.py +0 -0
  83. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/cli/__init__.py +0 -0
  84. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/cli/_download.py +0 -0
  85. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/cli/_traceback.py +0 -0
  86. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/cli/app.py +0 -0
  87. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/cli/cluster.py +0 -0
  88. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/cli/config.py +0 -0
  89. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/cli/container.py +0 -0
  90. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/cli/dict.py +0 -0
  91. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/cli/entry_point.py +0 -0
  92. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/cli/environment.py +0 -0
  93. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/cli/import_refs.py +0 -0
  94. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/cli/launch.py +0 -0
  95. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/cli/network_file_system.py +0 -0
  96. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/cli/profile.py +0 -0
  97. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/cli/programs/__init__.py +0 -0
  98. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/cli/programs/launch_instance_ssh.py +0 -0
  99. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/cli/programs/run_jupyter.py +0 -0
  100. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/cli/programs/run_marimo.py +0 -0
  101. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/cli/programs/vscode.py +0 -0
  102. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/cli/queues.py +0 -0
  103. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/cli/run.py +0 -0
  104. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/cli/secret.py +0 -0
  105. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/cli/token.py +0 -0
  106. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/cli/utils.py +0 -0
  107. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/cli/volume.py +0 -0
  108. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/client.py +0 -0
  109. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/cloud_bucket_mount.py +0 -0
  110. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/cloud_bucket_mount.pyi +0 -0
  111. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/cls.py +0 -0
  112. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/cls.pyi +0 -0
  113. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/config.py +0 -0
  114. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/container_process.py +0 -0
  115. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/container_process.pyi +0 -0
  116. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/dict.py +0 -0
  117. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/dict.pyi +0 -0
  118. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/environments.py +0 -0
  119. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/environments.pyi +0 -0
  120. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/exception.py +0 -0
  121. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/experimental/__init__.py +0 -0
  122. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/experimental/flash.py +0 -0
  123. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/experimental/flash.pyi +0 -0
  124. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/experimental/ipython.py +0 -0
  125. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/file_io.py +0 -0
  126. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/file_io.pyi +0 -0
  127. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/file_pattern_matcher.py +0 -0
  128. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/functions.py +0 -0
  129. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/functions.pyi +0 -0
  130. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/gpu.py +0 -0
  131. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/image.py +0 -0
  132. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/image.pyi +0 -0
  133. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/io_streams.py +0 -0
  134. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/io_streams.pyi +0 -0
  135. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/mount.py +0 -0
  136. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/mount.pyi +0 -0
  137. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/network_file_system.py +0 -0
  138. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/network_file_system.pyi +0 -0
  139. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/object.py +0 -0
  140. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/object.pyi +0 -0
  141. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/output.py +0 -0
  142. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/parallel_map.py +0 -0
  143. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/parallel_map.pyi +0 -0
  144. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/partial_function.py +0 -0
  145. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/partial_function.pyi +0 -0
  146. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/proxy.py +0 -0
  147. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/proxy.pyi +0 -0
  148. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/py.typed +0 -0
  149. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/queue.py +0 -0
  150. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/queue.pyi +0 -0
  151. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/retries.py +0 -0
  152. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/runner.py +0 -0
  153. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/runner.pyi +0 -0
  154. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/running_app.py +0 -0
  155. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/sandbox.py +0 -0
  156. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/sandbox.pyi +0 -0
  157. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/schedule.py +0 -0
  158. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/scheduler_placement.py +0 -0
  159. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/secret.py +0 -0
  160. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/secret.pyi +0 -0
  161. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/serving.py +0 -0
  162. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/serving.pyi +0 -0
  163. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/snapshot.py +0 -0
  164. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/snapshot.pyi +0 -0
  165. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/stream_type.py +0 -0
  166. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/token_flow.py +0 -0
  167. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/token_flow.pyi +0 -0
  168. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/volume.py +0 -0
  169. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal/volume.pyi +0 -0
  170. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal.egg-info/SOURCES.txt +0 -0
  171. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal.egg-info/dependency_links.txt +0 -0
  172. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal.egg-info/entry_points.txt +0 -0
  173. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal.egg-info/requires.txt +0 -0
  174. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal.egg-info/top_level.txt +0 -0
  175. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal_docs/__init__.py +0 -0
  176. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal_docs/gen_cli_docs.py +0 -0
  177. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal_docs/gen_reference_docs.py +0 -0
  178. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal_docs/mdmd/__init__.py +0 -0
  179. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal_docs/mdmd/mdmd.py +0 -0
  180. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal_docs/mdmd/signatures.py +0 -0
  181. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal_proto/__init__.py +0 -0
  182. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal_proto/api_pb2_grpc.py +0 -0
  183. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal_proto/api_pb2_grpc.pyi +0 -0
  184. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal_proto/modal_api_grpc.py +0 -0
  185. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal_proto/py.typed +0 -0
  186. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal_proto/sandbox_router.proto +0 -0
  187. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal_proto/sandbox_router_grpc.py +0 -0
  188. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal_proto/sandbox_router_pb2.py +0 -0
  189. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal_proto/sandbox_router_pb2.pyi +0 -0
  190. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal_proto/sandbox_router_pb2_grpc.py +0 -0
  191. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal_proto/sandbox_router_pb2_grpc.pyi +0 -0
  192. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal_proto/task_command_router.proto +0 -0
  193. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal_proto/task_command_router_grpc.py +0 -0
  194. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal_proto/task_command_router_pb2.py +0 -0
  195. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal_proto/task_command_router_pb2.pyi +0 -0
  196. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal_proto/task_command_router_pb2_grpc.py +0 -0
  197. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal_proto/task_command_router_pb2_grpc.pyi +0 -0
  198. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/modal_version/__main__.py +0 -0
  199. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/pyproject.toml +0 -0
  200. {modal-1.2.3.dev9 → modal-1.2.3.dev10}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.2.3.dev9
3
+ Version: 1.2.3.dev10
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License: Apache-2.0
@@ -9,7 +9,8 @@ import urllib.parse
9
9
  import uuid
10
10
  from collections.abc import AsyncIterator
11
11
  from dataclasses import dataclass, field
12
- from typing import Any, Optional, TypeVar
12
+ from functools import cache
13
+ from typing import Any, Optional, Sequence, TypeVar
13
14
 
14
15
  import grpclib.client
15
16
  import grpclib.config
@@ -17,11 +18,14 @@ import grpclib.events
17
18
  import grpclib.protocol
18
19
  import grpclib.stream
19
20
  from google.protobuf.message import Message
21
+ from google.protobuf.symbol_database import SymbolDatabase
20
22
  from grpclib import GRPCError, Status
23
+ from grpclib.encoding.base import StatusDetailsCodecBase
21
24
  from grpclib.exceptions import StreamTerminatedError
22
25
  from grpclib.protocol import H2Protocol
23
26
 
24
27
  from modal.exception import AuthError, ConnectionError
28
+ from modal_proto import api_pb2
25
29
  from modal_version import __version__
26
30
 
27
31
  from .._traceback import suppress_tb_frames
@@ -107,6 +111,56 @@ class ConnectionManager:
107
111
  self._channels.clear()
108
112
 
109
113
 
114
+ @cache
115
+ def _sym_db() -> SymbolDatabase:
116
+ from google.protobuf.symbol_database import Default
117
+
118
+ return Default()
119
+
120
+
121
+ class CustomProtoStatusDetailsCodec(StatusDetailsCodecBase):
122
+ """grpclib compatible details codec.
123
+
124
+ The server can encode the details using `google.rpc.Status` using grpclib's default codec and this custom codec
125
+ can decode it into a `api_pb2.RPCStatus`.
126
+ """
127
+
128
+ def encode(
129
+ self,
130
+ status: Status,
131
+ message: Optional[str],
132
+ details: Optional[Sequence[Message]],
133
+ ) -> bytes:
134
+ details_proto = api_pb2.RPCStatus(code=status.value, message=message or "")
135
+ if details is not None:
136
+ for detail in details:
137
+ detail_container = details_proto.details.add()
138
+ detail_container.Pack(detail)
139
+ return details_proto.SerializeToString()
140
+
141
+ def decode(
142
+ self,
143
+ status: Status,
144
+ message: Optional[str],
145
+ data: bytes,
146
+ ) -> Any:
147
+ sym_db = _sym_db()
148
+ details_proto = api_pb2.RPCStatus.FromString(data)
149
+
150
+ details = []
151
+ for detail_container in details_proto.details:
152
+ # If we do not know how to decode an emssage, we'll ignore it.
153
+ with contextlib.suppress(Exception):
154
+ msg_type = sym_db.GetSymbol(detail_container.TypeName())
155
+ detail = msg_type()
156
+ detail_container.Unpack(detail)
157
+ details.append(detail)
158
+ return details
159
+
160
+
161
+ custom_detail_codec = CustomProtoStatusDetailsCodec()
162
+
163
+
110
164
  def create_channel(
111
165
  server_url: str,
112
166
  metadata: dict[str, str] = {},
@@ -125,7 +179,7 @@ def create_channel(
125
179
  )
126
180
 
127
181
  if o.scheme == "unix":
128
- channel = grpclib.client.Channel(path=o.path, config=config) # probably pointless to use a pool ever
182
+ channel = grpclib.client.Channel(path=o.path, config=config, status_details_codec=custom_detail_codec)
129
183
  elif o.scheme in ("http", "https"):
130
184
  target = o.netloc
131
185
  parts = target.split(":")
@@ -133,7 +187,7 @@ def create_channel(
133
187
  ssl = o.scheme.endswith("s")
134
188
  host = parts[0]
135
189
  port = int(parts[1]) if len(parts) == 2 else 443 if ssl else 80
136
- channel = grpclib.client.Channel(host, port, ssl=ssl, config=config)
190
+ channel = grpclib.client.Channel(host, port, ssl=ssl, config=config, status_details_codec=custom_detail_codec)
137
191
  else:
138
192
  raise Exception(f"Unknown scheme: {o.scheme}")
139
193
 
@@ -258,7 +312,6 @@ async def _retry_transient_errors(
258
312
  raise AuthError(exc.message)
259
313
  else:
260
314
  raise exc
261
-
262
315
  if retry.max_retries is not None and n_retries >= retry.max_retries:
263
316
  final_attempt = True
264
317
  elif total_deadline is not None and time.time() + delay + retry.attempt_timeout_floor >= total_deadline:
@@ -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.2.3.dev9",
36
+ version: str = "1.2.3.dev10",
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.2.3.dev9",
167
+ version: str = "1.2.3.dev10",
168
168
  ):
169
169
  """mdmd:hidden
170
170
  The Modal client object is not intended to be instantiated directly by users.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.2.3.dev9
3
+ Version: 1.2.3.dev10
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License: Apache-2.0
@@ -4,6 +4,7 @@ option go_package = "github.com/modal-labs/modal/go/proto";
4
4
 
5
5
  package modal.client;
6
6
 
7
+ import "google/protobuf/any.proto";
7
8
  import "google/protobuf/empty.proto";
8
9
  import "google/protobuf/struct.proto";
9
10
  import "google/protobuf/timestamp.proto";
@@ -2045,6 +2046,7 @@ message GPUConfig {
2045
2046
  string gpu_type = 4;
2046
2047
  }
2047
2048
 
2049
+
2048
2050
  message GeneratorDone { // Sent as the output when a generator finishes running.
2049
2051
  uint64 items_total = 1;
2050
2052
  }
@@ -2086,6 +2088,7 @@ message GenericResult { // Used for both tasks and function outputs
2086
2088
  string propagation_reason = 13; // (?)
2087
2089
  }
2088
2090
 
2091
+
2089
2092
  message Image {
2090
2093
  repeated BaseImage base_images = 5;
2091
2094
  repeated string dockerfile_commands = 6;
@@ -2631,6 +2634,16 @@ message QueuePutRequest {
2631
2634
  int32 partition_ttl_seconds = 6;
2632
2635
  }
2633
2636
 
2637
+ // A copy google.rpc.Status for GRPCError.details:
2638
+ // https://github.com/googleapis/googleapis/blob/master/google/rpc/status.proto
2639
+ // RPCStatus is compatible with google.rpc.Status, so one can encode messages using
2640
+ // google.rpc.Status. The `details` field can be a list of any message, but for client
2641
+ // to decode it, the messages should be defined here (`modal_proto`).
2642
+ message RPCStatus {
2643
+ int32 code = 1;
2644
+ string message = 2;
2645
+ repeated google.protobuf.Any details = 3;
2646
+ }
2634
2647
 
2635
2648
  message RateLimit {
2636
2649
  int32 limit = 1;
@@ -9,6 +9,7 @@ import grpclib.client
9
9
  if typing.TYPE_CHECKING:
10
10
  import grpclib.server
11
11
 
12
+ import google.protobuf.any_pb2
12
13
  import google.protobuf.empty_pb2
13
14
  import google.protobuf.struct_pb2
14
15
  import google.protobuf.timestamp_pb2