modal 1.6.4.dev8__tar.gz → 1.6.4.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 (254) hide show
  1. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/PKG-INFO +1 -1
  2. modal-1.6.4.dev10/modal/_audit_logs/__init__.py +1 -0
  3. modal-1.6.4.dev10/modal/_audit_logs/_rpcs.py +66 -0
  4. modal-1.6.4.dev10/modal/_audit_logs/count.py +17 -0
  5. modal-1.6.4.dev10/modal/_audit_logs/list.py +83 -0
  6. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_image.py +5 -6
  7. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/cli/image.py +123 -0
  8. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/cli/shell.py +1 -1
  9. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/client.pyi +2 -2
  10. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/image.pyi +1 -0
  11. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal.egg-info/PKG-INFO +1 -1
  12. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal.egg-info/SOURCES.txt +4 -0
  13. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal_proto/api_grpc.py +64 -0
  14. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal_proto/api_pb2.py +1529 -1432
  15. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal_proto/api_pb2.pyi +232 -14
  16. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal_proto/api_pb2_grpc.py +135 -0
  17. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal_proto/api_pb2_grpc.pyi +46 -0
  18. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal_proto/modal_api_grpc.py +4 -0
  19. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal_version/__init__.py +1 -1
  20. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/LICENSE +0 -0
  21. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/README.md +0 -0
  22. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/__init__.py +0 -0
  23. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/__main__.py +0 -0
  24. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_billing.py +0 -0
  25. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_cluster.py +0 -0
  26. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_cluster.pyi +0 -0
  27. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_container_entrypoint.py +0 -0
  28. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_environments.py +0 -0
  29. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_function_variants.py +0 -0
  30. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_functions.py +0 -0
  31. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_grpc_client.py +0 -0
  32. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_ipython.py +0 -0
  33. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_load_context.py +0 -0
  34. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_location.py +0 -0
  35. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_logs.py +0 -0
  36. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_logs_manager.py +0 -0
  37. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_logs_manager.pyi +0 -0
  38. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_metrics.py +0 -0
  39. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_metrics.pyi +0 -0
  40. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_object.py +0 -0
  41. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_outbound_policy.py +0 -0
  42. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_outbound_policy.pyi +0 -0
  43. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_output/__init__.py +0 -0
  44. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_output/manager.py +0 -0
  45. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_output/pty.py +0 -0
  46. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_output/rich.py +0 -0
  47. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_output/status.py +0 -0
  48. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_partial_function.py +0 -0
  49. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_resolver.py +0 -0
  50. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_resources.py +0 -0
  51. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_runtime/__init__.py +0 -0
  52. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_runtime/asgi.py +0 -0
  53. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_runtime/container_io_manager.py +0 -0
  54. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_runtime/container_io_manager.pyi +0 -0
  55. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_runtime/execution_context.py +0 -0
  56. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_runtime/execution_context.pyi +0 -0
  57. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_runtime/gpu_memory_snapshot.py +0 -0
  58. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_runtime/task_lifecycle_manager.py +0 -0
  59. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_runtime/task_lifecycle_manager.pyi +0 -0
  60. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_runtime/telemetry.py +0 -0
  61. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_runtime/user_code_event_loop.py +0 -0
  62. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_runtime/user_code_imports.py +0 -0
  63. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_serialization.py +0 -0
  64. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_server.py +0 -0
  65. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_server.pyi +0 -0
  66. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_supports_logs.py +0 -0
  67. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_traceback.py +0 -0
  68. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_tunnel.py +0 -0
  69. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_tunnel.pyi +0 -0
  70. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_type_manager.py +0 -0
  71. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_utils/__init__.py +0 -0
  72. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_utils/app_utils.py +0 -0
  73. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_utils/async_utils.py +0 -0
  74. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_utils/auth_token_manager.py +0 -0
  75. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_utils/blob_utils.py +0 -0
  76. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_utils/browser_utils.py +0 -0
  77. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_utils/bytes_io_segment_payload.py +0 -0
  78. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_utils/curl_utils.py +0 -0
  79. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_utils/deprecation.py +0 -0
  80. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_utils/display_utils.py +0 -0
  81. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_utils/docker_utils.py +0 -0
  82. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_utils/function_utils.py +0 -0
  83. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_utils/git_utils.py +0 -0
  84. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_utils/grpc_testing.py +0 -0
  85. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_utils/grpc_utils.py +0 -0
  86. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_utils/hash_utils.py +0 -0
  87. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_utils/http_utils.py +0 -0
  88. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_utils/idle_countdown.py +0 -0
  89. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_utils/jwt_utils.py +0 -0
  90. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_utils/logger.py +0 -0
  91. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_utils/mount_utils.py +0 -0
  92. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_utils/name_utils.py +0 -0
  93. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_utils/oauth.py +0 -0
  94. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_utils/package_utils.py +0 -0
  95. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_utils/pattern_utils.py +0 -0
  96. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_utils/proxy_support.py +0 -0
  97. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_utils/rand_pb_testing.py +0 -0
  98. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_utils/sandbox_fs_utils.py +0 -0
  99. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_utils/shell_utils.py +0 -0
  100. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_utils/time_utils.py +0 -0
  101. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_vendor/__init__.py +0 -0
  102. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_vendor/a2wsgi_wsgi.py +0 -0
  103. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_vendor/cloudpickle.py +0 -0
  104. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_vendor/tblib.py +0 -0
  105. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_vendor/version.py +0 -0
  106. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_watcher.py +0 -0
  107. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/_workspace.py +0 -0
  108. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/app.py +0 -0
  109. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/app.pyi +0 -0
  110. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/billing.py +0 -0
  111. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/billing.pyi +0 -0
  112. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/builder/2023.12.312.txt +0 -0
  113. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/builder/2023.12.txt +0 -0
  114. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/builder/2024.04.txt +0 -0
  115. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/builder/2024.10.txt +0 -0
  116. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/builder/2025.06.txt +0 -0
  117. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/builder/2026.10.txt +0 -0
  118. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/builder/PREVIEW.txt +0 -0
  119. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/builder/README.md +0 -0
  120. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/builder/base-images.json +0 -0
  121. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/call_graph.py +0 -0
  122. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/cli/__init__.py +0 -0
  123. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/cli/_download.py +0 -0
  124. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/cli/_help.py +0 -0
  125. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/cli/_logs.py +0 -0
  126. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/cli/_stats.py +0 -0
  127. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/cli/_traceback.py +0 -0
  128. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/cli/app.py +0 -0
  129. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/cli/billing.py +0 -0
  130. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/cli/changelog.py +0 -0
  131. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/cli/config.py +0 -0
  132. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/cli/container.py +0 -0
  133. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/cli/curl.py +0 -0
  134. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/cli/dashboard.py +0 -0
  135. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/cli/dict.py +0 -0
  136. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/cli/endpoint.py +0 -0
  137. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/cli/entry_point.py +0 -0
  138. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/cli/environment.py +0 -0
  139. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/cli/function.py +0 -0
  140. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/cli/import_refs.py +0 -0
  141. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/cli/logo.py +0 -0
  142. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/cli/network_file_system.py +0 -0
  143. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/cli/profile.py +0 -0
  144. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/cli/queues.py +0 -0
  145. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/cli/run.py +0 -0
  146. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/cli/secret.py +0 -0
  147. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/cli/selector.py +0 -0
  148. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/cli/server.py +0 -0
  149. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/cli/skills.py +0 -0
  150. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/cli/token.py +0 -0
  151. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/cli/utils.py +0 -0
  152. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/cli/volume.py +0 -0
  153. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/cli/workspace.py +0 -0
  154. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/client.py +0 -0
  155. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/cloud_bucket_mount.py +0 -0
  156. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/cloud_bucket_mount.pyi +0 -0
  157. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/cls.py +0 -0
  158. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/cls.pyi +0 -0
  159. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/cluster.py +0 -0
  160. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/cluster.pyi +0 -0
  161. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/config.py +0 -0
  162. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/container_process.py +0 -0
  163. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/container_process.pyi +0 -0
  164. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/dict.py +0 -0
  165. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/dict.pyi +0 -0
  166. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/environments.py +0 -0
  167. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/environments.pyi +0 -0
  168. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/exception.py +0 -0
  169. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/experimental/__init__.py +0 -0
  170. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/experimental/_flash_container_entry.py +0 -0
  171. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/experimental/flash.py +0 -0
  172. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/experimental/flash.pyi +0 -0
  173. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/experimental/flash_server.py +0 -0
  174. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/experimental/flash_server.pyi +0 -0
  175. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/experimental/ipython.py +0 -0
  176. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/file_pattern_matcher.py +0 -0
  177. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/functions.py +0 -0
  178. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/functions.pyi +0 -0
  179. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/image.py +0 -0
  180. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/io_streams.py +0 -0
  181. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/io_streams.pyi +0 -0
  182. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/mount.py +0 -0
  183. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/mount.pyi +0 -0
  184. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/network_file_system.py +0 -0
  185. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/network_file_system.pyi +0 -0
  186. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/object.py +0 -0
  187. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/object.pyi +0 -0
  188. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/output.py +0 -0
  189. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/parallel_map.py +0 -0
  190. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/parallel_map.pyi +0 -0
  191. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/partial_function.py +0 -0
  192. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/partial_function.pyi +0 -0
  193. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/proxy.py +0 -0
  194. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/proxy.pyi +0 -0
  195. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/py.typed +0 -0
  196. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/queue.py +0 -0
  197. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/queue.pyi +0 -0
  198. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/retries.py +0 -0
  199. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/runner.py +0 -0
  200. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/runner.pyi +0 -0
  201. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/running_app.py +0 -0
  202. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/sandbox/__init__.py +0 -0
  203. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/sandbox/_common.py +0 -0
  204. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/sandbox/_filesystem.py +0 -0
  205. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/sandbox/_impl_persistent.py +0 -0
  206. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/sandbox/_impl_v1.py +0 -0
  207. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/sandbox/_impl_v2.py +0 -0
  208. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/sandbox/_sandbox.py +0 -0
  209. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/sandbox/_sidecar.py +0 -0
  210. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/sandbox/_snapshot.py +0 -0
  211. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/sandbox/_task_command_router_client.py +0 -0
  212. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/sandbox/sandbox.py +0 -0
  213. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/sandbox/sandbox.pyi +0 -0
  214. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/schedule.py +0 -0
  215. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/scheduler_placement.py +0 -0
  216. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/secret.py +0 -0
  217. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/secret.pyi +0 -0
  218. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/server.py +0 -0
  219. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/server.pyi +0 -0
  220. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/serving.py +0 -0
  221. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/serving.pyi +0 -0
  222. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/skills/modal/SKILL.md +0 -0
  223. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/stream_type.py +0 -0
  224. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/token_flow.py +0 -0
  225. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/token_flow.pyi +0 -0
  226. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/types.py +0 -0
  227. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/volume.py +0 -0
  228. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/volume.pyi +0 -0
  229. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/workspace.py +0 -0
  230. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal/workspace.pyi +0 -0
  231. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal.egg-info/dependency_links.txt +0 -0
  232. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal.egg-info/entry_points.txt +0 -0
  233. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal.egg-info/requires.txt +0 -0
  234. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal.egg-info/top_level.txt +0 -0
  235. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal_docs/__init__.py +0 -0
  236. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal_docs/gen_cli_docs.py +0 -0
  237. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal_docs/gen_cli_docs_main.py +0 -0
  238. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal_docs/gen_reference_docs.py +0 -0
  239. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal_docs/gen_reference_docs_main.py +0 -0
  240. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal_docs/mdmd/__init__.py +0 -0
  241. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal_docs/mdmd/mdmd.py +0 -0
  242. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal_docs/mdmd/signatures.py +0 -0
  243. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal_docs/mdmd/types.py +0 -0
  244. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal_docs/reference_intro.md +0 -0
  245. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal_proto/__init__.py +0 -0
  246. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal_proto/py.typed +0 -0
  247. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal_proto/task_command_router_grpc.py +0 -0
  248. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal_proto/task_command_router_pb2.py +0 -0
  249. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal_proto/task_command_router_pb2.pyi +0 -0
  250. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal_proto/task_command_router_pb2_grpc.py +0 -0
  251. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal_proto/task_command_router_pb2_grpc.pyi +0 -0
  252. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/modal_version/__main__.py +0 -0
  253. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/pyproject.toml +0 -0
  254. {modal-1.6.4.dev8 → modal-1.6.4.dev10}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.6.4.dev8
3
+ Version: 1.6.4.dev10
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License-Expression: Apache-2.0
@@ -0,0 +1 @@
1
+ # Copyright Modal Labs 2026
@@ -0,0 +1,66 @@
1
+ # Copyright Modal Labs 2026
2
+ """The audit log RPCs, one call each, retried with backoff. Ordering and batching live in list.py."""
3
+
4
+ from __future__ import annotations
5
+
6
+ from collections.abc import Awaitable, Callable
7
+ from typing import TYPE_CHECKING, TypeVar
8
+
9
+ from modal._utils.grpc_utils import Retry
10
+ from modal_proto import api_pb2
11
+
12
+ if TYPE_CHECKING:
13
+ from modal.client import _Client
14
+
15
+
16
+ _Resp = TypeVar("_Resp")
17
+
18
+
19
+ _MAX_RETRIES = 4
20
+ _PLAN_MAX_RETRIES = 2
21
+
22
+
23
+ async def _call(
24
+ rpc: Callable[..., Awaitable[_Resp]], req: object, *, timeout: float, max_retries: int = _MAX_RETRIES
25
+ ) -> _Resp:
26
+ """Call with backoff on timeouts and transient errors; rate and resource limits wait as the server says."""
27
+ retry = Retry(base_delay=1.0, delay_factor=2.0, max_delay=8.0, max_retries=max_retries, attempt_timeout=timeout)
28
+ return await rpc(req, retry=retry)
29
+
30
+
31
+ async def get_settings(client: _Client) -> api_pb2.AuditLogSettingsGetResponse:
32
+ return await client._stub.AuditLogSettingsGet(api_pb2.AuditLogSettingsGetRequest())
33
+
34
+
35
+ async def count_entries(
36
+ client: _Client, q: str, oldest_ms: int, newest_ms: int, config: api_pb2.AuditLogSettingsGetResponse
37
+ ) -> int:
38
+ req = api_pb2.AuditLogCountRequest(q=q, oldest_ms=oldest_ms, newest_ms=newest_ms)
39
+ resp = await _call(client._stub.AuditLogCount, req, timeout=config.request_timeout_secs)
40
+ return resp.count
41
+
42
+
43
+ async def list_page(
44
+ client: _Client,
45
+ q: str,
46
+ oldest_ms: int,
47
+ newest_ms: int,
48
+ limit: int,
49
+ config: api_pb2.AuditLogSettingsGetResponse,
50
+ newest_cursor: api_pb2.AuditLogCursor | None = None,
51
+ oldest_cursor: api_pb2.AuditLogCursor | None = None,
52
+ ) -> api_pb2.AuditLogListResponse:
53
+ req = api_pb2.AuditLogListRequest(q=q, oldest_ms=oldest_ms, newest_ms=newest_ms, limit=limit)
54
+ if newest_cursor is not None:
55
+ req.newest_cursor.CopyFrom(newest_cursor)
56
+ if oldest_cursor is not None:
57
+ req.oldest_cursor.CopyFrom(oldest_cursor)
58
+ return await _call(client._stub.AuditLogList, req, timeout=config.request_timeout_secs)
59
+
60
+
61
+ async def plan_buckets(
62
+ client: _Client, q: str, oldest_ms: int, newest_ms: int, config: api_pb2.AuditLogSettingsGetResponse
63
+ ) -> list[api_pb2.AuditLogCursor]:
64
+ req = api_pb2.AuditLogBucketsRequest(q=q, oldest_ms=oldest_ms, newest_ms=newest_ms, bucket_size=config.bucket_size)
65
+ resp = await _call(client._stub.AuditLogPlan, req, timeout=config.plan_timeout_secs, max_retries=_PLAN_MAX_RETRIES)
66
+ return list(resp.cursors)
@@ -0,0 +1,17 @@
1
+ # Copyright Modal Labs 2026
2
+ from __future__ import annotations
3
+
4
+ from typing import TYPE_CHECKING
5
+
6
+ from modal._audit_logs import _rpcs
7
+ from modal_proto import api_pb2
8
+
9
+ if TYPE_CHECKING:
10
+ from modal.client import _Client
11
+
12
+
13
+ async def count_audit_logs(
14
+ client: _Client, q: str, oldest_ms: int, newest_ms: int, config: api_pb2.AuditLogSettingsGetResponse
15
+ ) -> int:
16
+ """Count the entries in [oldest_ms, newest_ms) that match the query."""
17
+ return await _rpcs.count_entries(client, q, oldest_ms, newest_ms, config)
@@ -0,0 +1,83 @@
1
+ # Copyright Modal Labs 2026
2
+ from __future__ import annotations
3
+
4
+ from collections.abc import AsyncGenerator
5
+ from contextlib import aclosing
6
+
7
+ from modal._audit_logs import _rpcs
8
+ from modal._utils.async_utils import async_map_ordered
9
+ from modal.client import _Client
10
+ from modal_proto import api_pb2
11
+
12
+ # (newest_cursor, oldest_cursor); None where the bucket is open-ended.
13
+ Bucket = tuple[api_pb2.AuditLogCursor | None, api_pb2.AuditLogCursor | None]
14
+
15
+
16
+ async def get_bucket_cursors(
17
+ client: _Client, q: str, oldest_ms: int, newest_ms: int, config: api_pb2.AuditLogSettingsGetResponse
18
+ ) -> list[Bucket]:
19
+ """Split the range into buckets, as (newest_cursor, oldest_cursor) pairs ordered oldest to newest.
20
+
21
+ The first bucket has no oldest cursor and the last has no newest cursor.
22
+ """
23
+ cursors = await _rpcs.plan_buckets(client, q, oldest_ms, newest_ms, config)
24
+ return list(zip([None, *cursors], [*cursors, None]))[::-1]
25
+
26
+
27
+ async def _fetch_bucket(
28
+ client: _Client,
29
+ q: str,
30
+ oldest_ms: int,
31
+ newest_ms: int,
32
+ config: api_pb2.AuditLogSettingsGetResponse,
33
+ bucket: Bucket,
34
+ ) -> list[api_pb2.AuditLogEntry]:
35
+ """Read one bucket's entries, oldest to newest, using pagination"""
36
+ newest_cursor, oldest_cursor = bucket
37
+ entries: list[api_pb2.AuditLogEntry] = []
38
+ while True:
39
+ resp = await _rpcs.list_page(
40
+ client, q, oldest_ms, newest_ms, config.page_size, config, newest_cursor, oldest_cursor
41
+ )
42
+ entries.extend(resp.items)
43
+ # Skips the empty request a full last page would otherwise trigger; an unset next_cursor also ends the loop.
44
+ if oldest_cursor is not None and resp.items and resp.items[-1].id == oldest_cursor.id:
45
+ break
46
+ if not resp.HasField("next_cursor"):
47
+ break
48
+ newest_cursor = resp.next_cursor
49
+ entries.reverse()
50
+ return entries
51
+
52
+
53
+ async def fetch_audit_logs(
54
+ q: str,
55
+ oldest_ms: int,
56
+ newest_ms: int,
57
+ *,
58
+ client: _Client | None = None,
59
+ config: api_pb2.AuditLogSettingsGetResponse,
60
+ ) -> AsyncGenerator[api_pb2.AuditLogEntry]:
61
+ """Yield the range's entries from the oldest to the newest, one bucket at a time.
62
+
63
+ At most `max_concurrent_requests` buckets are fetched at once, and at most `max_buffered_buckets` are fetched
64
+ or held at once. A new bucket is admitted only after the consumer has taken all of a bucket's entries, so a slow
65
+ consumer or a stalled request cannot grow memory.
66
+ If any request fails after its attempts, the remaining requests are cancelled and the error is raised.
67
+ """
68
+ if client is None:
69
+ client = await _Client.from_env()
70
+ buckets = await get_bucket_cursors(client, q, oldest_ms, newest_ms, config)
71
+
72
+ async def bucket_stream() -> AsyncGenerator[Bucket]:
73
+ for bucket in buckets:
74
+ yield bucket
75
+
76
+ async def fetch(bucket: Bucket) -> list[api_pb2.AuditLogEntry]:
77
+ return await _fetch_bucket(client, q, oldest_ms, newest_ms, config, bucket)
78
+
79
+ fetched = async_map_ordered(bucket_stream(), fetch, config.max_concurrent_requests, config.max_buffered_buckets)
80
+ async with aclosing(fetched) as stream:
81
+ async for entries in stream:
82
+ for entry in entries:
83
+ yield entry
@@ -584,6 +584,7 @@ class _Image(_Object, type_prefix="im"):
584
584
  ] # added as mounts on any container referencing the Image, see `def _mount_layers`
585
585
  _added_python_source_set: frozenset[str] # used to warn about missing mounts during auto-mount deprecation
586
586
  _metadata: api_pb2.ImageMetadata | None = None # set on hydration, private for now
587
+ _cache_hit: bool | None = None # set when built, True if an existing build was reused
587
588
  _is_empty: bool
588
589
  _build_steps: list[api_pb2.ImageBuildStep] | None = None
589
590
  # A failed image ID is only queryable through the client that performed the build.
@@ -832,6 +833,7 @@ class _Image(_Object, type_prefix="im"):
832
833
  result: api_pb2.GenericResult
833
834
  metadata: api_pb2.ImageMetadata | None = None
834
835
 
836
+ self._cache_hit = bool(resp.result.status)
835
837
  if resp.result.status:
836
838
  # image already built
837
839
  result = resp.result
@@ -2062,8 +2064,7 @@ class _Image(_Object, type_prefix="im"):
2062
2064
  if not isinstance(entrypoint_commands, list) or not all(isinstance(x, str) for x in entrypoint_commands):
2063
2065
  raise InvalidError("entrypoint_commands must be a list of strings.")
2064
2066
  args = _flatten_str_args("entrypoint", "entrypoint_commands", entrypoint_commands)
2065
- args_str = '"' + '", "'.join(args) + '"' if args else ""
2066
- dockerfile_cmd = f"ENTRYPOINT [{args_str}]"
2067
+ dockerfile_cmd = f"ENTRYPOINT {json.dumps(args, ensure_ascii=False)}"
2067
2068
 
2068
2069
  return self.dockerfile_commands(dockerfile_cmd)
2069
2070
 
@@ -2083,8 +2084,7 @@ class _Image(_Object, type_prefix="im"):
2083
2084
  if not isinstance(shell_commands, list) or not all(isinstance(x, str) for x in shell_commands):
2084
2085
  raise InvalidError("shell_commands must be a list of strings.")
2085
2086
  args = _flatten_str_args("shell", "shell_commands", shell_commands)
2086
- args_str = '"' + '", "'.join(args) + '"' if args else ""
2087
- dockerfile_cmd = f"SHELL [{args_str}]"
2087
+ dockerfile_cmd = f"SHELL {json.dumps(args, ensure_ascii=False)}"
2088
2088
 
2089
2089
  return self.dockerfile_commands(dockerfile_cmd)
2090
2090
 
@@ -3074,8 +3074,7 @@ class _Image(_Object, type_prefix="im"):
3074
3074
  raise InvalidError("Image CMD must be a list of strings.")
3075
3075
 
3076
3076
  cmd_args = _flatten_str_args("cmd", "cmd", cmd)
3077
- cmd_str = '"' + '", "'.join(cmd_args) + '"' if cmd_args else ""
3078
- dockerfile_cmd = f"CMD [{cmd_str}]"
3077
+ dockerfile_cmd = f"CMD {json.dumps(cmd_args, ensure_ascii=False)}"
3079
3078
 
3080
3079
  return self.dockerfile_commands(dockerfile_cmd)
3081
3080
 
@@ -42,6 +42,26 @@ def _print_result_summary(count: int) -> None:
42
42
  OutputManager.get().print(f"Showing {count} {result_label}")
43
43
 
44
44
 
45
+ async def _build_and_publish(image: _Image, image_ref: str, app: _App, env: str, name: Optional[str]) -> None:
46
+ built_image = await image.build(app)
47
+
48
+ output_mgr = OutputManager.get()
49
+ if built_image._cache_hit:
50
+ message = f"Used a cached pull of [bold]{image_ref}[/bold] as [bold]{built_image.object_id}[/bold]"
51
+ # A digest reference can't change in the registry, so pulling it again would be a no-op
52
+ if "@" not in image_ref:
53
+ message += " [dim](Pass --force-build to pull it from the registry again.)[/dim]"
54
+ output_mgr.step_completed(message)
55
+ else:
56
+ output_mgr.step_completed(f"Pulled [bold]{image_ref}[/bold] as [bold]{built_image.object_id}[/bold]")
57
+ if name:
58
+ upgraded_image_name = _upgrade_image_name(name, fallback_environment_name=env)
59
+ await built_image.publish(upgraded_image_name)
60
+ output_mgr.step_completed(f"Image published as [bold magenta]{upgraded_image_name}[/bold magenta]! 🎉")
61
+ output_mgr.print("\nUse it with:\n")
62
+ output_mgr.print(Syntax(f'modal.Image.from_name("{upgraded_image_name}")', "python"))
63
+
64
+
45
65
  async def _registry_secret(
46
66
  secret_name: Optional[str], secret_vars: Optional[str], env: str
47
67
  ) -> tuple[Optional[_Secret], set[str]]:
@@ -56,6 +76,15 @@ async def _registry_secret(
56
76
  return _Secret.from_local_environ(keys), set(keys)
57
77
 
58
78
 
79
+ def _check_registry_host(image_ref: str) -> None:
80
+ first, sep, _ = image_ref.partition("/")
81
+ # A leading path component is a registry host only if it looks like one; otherwise it's a Docker Hub name
82
+ if not sep or ("." not in first and ":" not in first and first != "localhost"):
83
+ raise click.UsageError(
84
+ f"IMAGE_REF must start with the registry host, e.g. docker.io/{image_ref} for a Docker Hub image."
85
+ )
86
+
87
+
59
88
  @image_cli.command("build", no_args_is_help=True)
60
89
  @click.argument("context_dir", metavar="CONTEXT_DIR")
61
90
  @click.option(
@@ -154,6 +183,100 @@ async def build(
154
183
  output_mgr.print(Syntax(f'modal.Image.from_name("{tag}")', "python"))
155
184
 
156
185
 
186
+ @image_cli.command("pull", no_args_is_help=True)
187
+ @click.argument("image_ref")
188
+ @click.option(
189
+ "--name",
190
+ "name",
191
+ metavar="[ENV/]NAME[:TAG]",
192
+ help="Publish the pulled Image under this name. An ENV/ prefix publishes it to that Environment.",
193
+ )
194
+ @click.option(
195
+ "--registry-secret",
196
+ "registry_secret_name",
197
+ default=None,
198
+ help="Name of a modal.Secret holding registry credentials.",
199
+ )
200
+ @click.option(
201
+ "--registry-secret-from-env",
202
+ "registry_secret_vars",
203
+ default=None,
204
+ metavar="VAR[,VAR...]",
205
+ help=(
206
+ "Comma-separated local environment variable names holding registry credentials. "
207
+ "Cannot be combined with --registry-secret."
208
+ ),
209
+ )
210
+ @click.option(
211
+ "--force-build",
212
+ is_flag=True,
213
+ help="Pull the image from the registry again, replacing a cached Image.",
214
+ )
215
+ @env_option
216
+ @synchronizer.create_blocking
217
+ async def pull(
218
+ image_ref: str,
219
+ *,
220
+ name: Optional[str] = None,
221
+ registry_secret_name: Optional[str] = None,
222
+ registry_secret_vars: Optional[str] = None,
223
+ force_build: bool = False,
224
+ env: Optional[str] = None,
225
+ ) -> None:
226
+ """Pull an Image from a container registry into Modal.
227
+
228
+ The `image_ref` is a registry image name (and optional tag), as passed to `modal.Image.from_registry`.
229
+ It must start with the registry host, e.g. `docker.io/node:20` for a Docker Hub image.
230
+ If `--name` is provided, the Modal Image will also be published under that name.
231
+ Use `ENV/NAME` to publish to another Environment; `--env` still selects the Environment
232
+ used for the pull and for looking up `--registry-secret`.
233
+
234
+ Examples:
235
+
236
+ ```bash
237
+ modal image pull docker.io/node:20
238
+ modal image pull nvcr.io/nvidia/pytorch:25.01-py3 --name pytorch:25
239
+ modal image pull docker.io/node:20 --name prod/node:20
240
+ ```
241
+
242
+ Pass `--force-build` to pull a tag again after it changes in the registry, e.g. `latest`.
243
+
244
+ Private registries need credentials from a `modal.Secret`, either one that already exists
245
+ (`--registry-secret`) or one assembled from local environment variables (`--registry-secret-from-env`).
246
+ The kind of authentication follows from the keys in the credentials:
247
+
248
+ - AWS: `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY` and `AWS_REGION` (optionally `AWS_SESSION_TOKEN`),
249
+ or `AWS_ROLE_ARN` and `AWS_REGION` to assume a role with OIDC
250
+ - GCP: `SERVICE_ACCOUNT_JSON`, holding the service account key's JSON
251
+ - Username and password: `REGISTRY_USERNAME` and `REGISTRY_PASSWORD`
252
+
253
+ ```bash
254
+ # Authenticate with a named Secret
255
+ modal image pull ghcr.io/my-org/my-image --registry-secret my-registry-secret
256
+
257
+ # Authenticate with credentials in environment variables
258
+ modal image pull $AWS_ECR_URL/my-image \\
259
+ --registry-secret-from-env AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY,AWS_REGION
260
+ ```
261
+
262
+ """
263
+ _check_registry_host(image_ref)
264
+ env = ensure_env(env)
265
+ secret, keys = await _registry_secret(registry_secret_name, registry_secret_vars, env)
266
+ if secret is not None:
267
+ # Fail before creating the app; from_registry runs the same check during the build
268
+ try:
269
+ _infer_registry_auth_type(keys)
270
+ except InvalidError as exc:
271
+ raise click.UsageError(str(exc)) from exc
272
+ image = _Image.from_registry(image_ref, secret, force_build=force_build)
273
+
274
+ app = _App("modal-image-pull")
275
+ async with _run_app(app, environment_name=env, stream_output=False):
276
+ OutputManager.get().print(f"Pulling [bold]{image_ref}[/bold]")
277
+ await _build_and_publish(image, image_ref, app, env, name)
278
+
279
+
157
280
  @image_cli.command("logs", no_args_is_help=True)
158
281
  @click.argument("image_id")
159
282
  @click.option(
@@ -448,7 +448,7 @@ def shell(
448
448
  app = App("modal shell")
449
449
 
450
450
  # NB: invoking under bash makes --cmd a lot more flexible.
451
- cmds = shlex.split(f'/bin/bash -c "{cmd}"')
451
+ cmds = ["/bin/bash", "-c", cmd]
452
452
  timeout = 3600
453
453
  parsed_experimental_options = _parse_experimental_options(experimental_options)
454
454
 
@@ -87,7 +87,7 @@ class _Client:
87
87
  server_url: str,
88
88
  client_type: int,
89
89
  credentials: typing.Optional[tuple[str, str]],
90
- version: str = "1.6.4.dev8",
90
+ version: str = "1.6.4.dev10",
91
91
  *,
92
92
  oauth_credentials: typing.Optional[_OAuthCredentials] = None,
93
93
  ):
@@ -304,7 +304,7 @@ class Client:
304
304
  server_url: str,
305
305
  client_type: int,
306
306
  credentials: typing.Optional[tuple[str, str]],
307
- version: str = "1.6.4.dev8",
307
+ version: str = "1.6.4.dev10",
308
308
  *,
309
309
  oauth_credentials: typing.Optional[_OAuthCredentials] = None,
310
310
  ):
@@ -32,6 +32,7 @@ class Image(modal.object.Object):
32
32
  _deferred_mounts: collections.abc.Sequence[modal.mount.Mount]
33
33
  _added_python_source_set: frozenset[str]
34
34
  _metadata: typing.Optional[modal_proto.api_pb2.ImageMetadata]
35
+ _cache_hit: typing.Optional[bool]
35
36
  _is_empty: bool
36
37
  _build_steps: typing.Optional[list[modal_proto.api_pb2.ImageBuildStep]]
37
38
  _failed_build_attempt: typing.Optional[modal._image._FailedBuildAttempt]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.6.4.dev8
3
+ Version: 1.6.4.dev10
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License-Expression: Apache-2.0
@@ -106,6 +106,10 @@ modal.egg-info/dependency_links.txt
106
106
  modal.egg-info/entry_points.txt
107
107
  modal.egg-info/requires.txt
108
108
  modal.egg-info/top_level.txt
109
+ modal/_audit_logs/__init__.py
110
+ modal/_audit_logs/_rpcs.py
111
+ modal/_audit_logs/count.py
112
+ modal/_audit_logs/list.py
109
113
  modal/_output/__init__.py
110
114
  modal/_output/manager.py
111
115
  modal/_output/pty.py
@@ -163,6 +163,10 @@ class ModalClientBase(abc.ABC):
163
163
  async def ClassGet(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.ClassGetRequest, modal_proto.api_pb2.ClassGetResponse]') -> None:
164
164
  pass
165
165
 
166
+ @abc.abstractmethod
167
+ async def CliCommandSuggest(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.CliCommandSuggestRequest, modal_proto.api_pb2.CliCommandSuggestResponse]') -> None:
168
+ pass
169
+
166
170
  @abc.abstractmethod
167
171
  async def ClientHello(self, stream: 'grpclib.server.Stream[google.protobuf.empty_pb2.Empty, modal_proto.api_pb2.ClientHelloResponse]') -> None:
168
172
  pass
@@ -587,6 +591,10 @@ class ModalClientBase(abc.ABC):
587
591
  async def MountPutFile(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.MountPutFileRequest, modal_proto.api_pb2.MountPutFileResponse]') -> None:
588
592
  pass
589
593
 
594
+ @abc.abstractmethod
595
+ async def ObjectSuggest(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.ObjectSuggestRequest, modal_proto.api_pb2.ObjectSuggestResponse]') -> None:
596
+ pass
597
+
590
598
  @abc.abstractmethod
591
599
  async def PersistentSandboxCreate(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.PersistentSandboxCreateRequest, modal_proto.api_pb2.PersistentSandboxCreateResponse]') -> None:
592
600
  pass
@@ -719,6 +727,14 @@ class ModalClientBase(abc.ABC):
719
727
  async def SandboxGetResourceUsage(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.SandboxGetResourceUsageRequest, modal_proto.api_pb2.SandboxGetResourceUsageResponse]') -> None:
720
728
  pass
721
729
 
730
+ @abc.abstractmethod
731
+ async def SandboxGetStats(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.SandboxGetStatsRequest, modal_proto.api_pb2.SandboxGetStatsResponse]') -> None:
732
+ pass
733
+
734
+ @abc.abstractmethod
735
+ async def SandboxGetStatsV2(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.SandboxGetStatsRequest, modal_proto.api_pb2.SandboxGetStatsResponse]') -> None:
736
+ pass
737
+
722
738
  @abc.abstractmethod
723
739
  async def SandboxGetTaskId(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.SandboxGetTaskIdRequest, modal_proto.api_pb2.SandboxGetTaskIdResponse]') -> None:
724
740
  pass
@@ -1341,6 +1357,12 @@ class ModalClientBase(abc.ABC):
1341
1357
  modal_proto.api_pb2.ClassGetRequest,
1342
1358
  modal_proto.api_pb2.ClassGetResponse,
1343
1359
  ),
1360
+ '/modal.client.ModalClient/CliCommandSuggest': grpclib.const.Handler(
1361
+ self.CliCommandSuggest,
1362
+ grpclib.const.Cardinality.UNARY_UNARY,
1363
+ modal_proto.api_pb2.CliCommandSuggestRequest,
1364
+ modal_proto.api_pb2.CliCommandSuggestResponse,
1365
+ ),
1344
1366
  '/modal.client.ModalClient/ClientHello': grpclib.const.Handler(
1345
1367
  self.ClientHello,
1346
1368
  grpclib.const.Cardinality.UNARY_UNARY,
@@ -1977,6 +1999,12 @@ class ModalClientBase(abc.ABC):
1977
1999
  modal_proto.api_pb2.MountPutFileRequest,
1978
2000
  modal_proto.api_pb2.MountPutFileResponse,
1979
2001
  ),
2002
+ '/modal.client.ModalClient/ObjectSuggest': grpclib.const.Handler(
2003
+ self.ObjectSuggest,
2004
+ grpclib.const.Cardinality.UNARY_UNARY,
2005
+ modal_proto.api_pb2.ObjectSuggestRequest,
2006
+ modal_proto.api_pb2.ObjectSuggestResponse,
2007
+ ),
1980
2008
  '/modal.client.ModalClient/PersistentSandboxCreate': grpclib.const.Handler(
1981
2009
  self.PersistentSandboxCreate,
1982
2010
  grpclib.const.Cardinality.UNARY_UNARY,
@@ -2175,6 +2203,18 @@ class ModalClientBase(abc.ABC):
2175
2203
  modal_proto.api_pb2.SandboxGetResourceUsageRequest,
2176
2204
  modal_proto.api_pb2.SandboxGetResourceUsageResponse,
2177
2205
  ),
2206
+ '/modal.client.ModalClient/SandboxGetStats': grpclib.const.Handler(
2207
+ self.SandboxGetStats,
2208
+ grpclib.const.Cardinality.UNARY_UNARY,
2209
+ modal_proto.api_pb2.SandboxGetStatsRequest,
2210
+ modal_proto.api_pb2.SandboxGetStatsResponse,
2211
+ ),
2212
+ '/modal.client.ModalClient/SandboxGetStatsV2': grpclib.const.Handler(
2213
+ self.SandboxGetStatsV2,
2214
+ grpclib.const.Cardinality.UNARY_UNARY,
2215
+ modal_proto.api_pb2.SandboxGetStatsRequest,
2216
+ modal_proto.api_pb2.SandboxGetStatsResponse,
2217
+ ),
2178
2218
  '/modal.client.ModalClient/SandboxGetTaskId': grpclib.const.Handler(
2179
2219
  self.SandboxGetTaskId,
2180
2220
  grpclib.const.Cardinality.UNARY_UNARY,
@@ -3003,6 +3043,12 @@ class ModalClientStub:
3003
3043
  modal_proto.api_pb2.ClassGetRequest,
3004
3044
  modal_proto.api_pb2.ClassGetResponse,
3005
3045
  )
3046
+ self.CliCommandSuggest = grpclib.client.UnaryUnaryMethod(
3047
+ channel,
3048
+ '/modal.client.ModalClient/CliCommandSuggest',
3049
+ modal_proto.api_pb2.CliCommandSuggestRequest,
3050
+ modal_proto.api_pb2.CliCommandSuggestResponse,
3051
+ )
3006
3052
  self.ClientHello = grpclib.client.UnaryUnaryMethod(
3007
3053
  channel,
3008
3054
  '/modal.client.ModalClient/ClientHello',
@@ -3639,6 +3685,12 @@ class ModalClientStub:
3639
3685
  modal_proto.api_pb2.MountPutFileRequest,
3640
3686
  modal_proto.api_pb2.MountPutFileResponse,
3641
3687
  )
3688
+ self.ObjectSuggest = grpclib.client.UnaryUnaryMethod(
3689
+ channel,
3690
+ '/modal.client.ModalClient/ObjectSuggest',
3691
+ modal_proto.api_pb2.ObjectSuggestRequest,
3692
+ modal_proto.api_pb2.ObjectSuggestResponse,
3693
+ )
3642
3694
  self.PersistentSandboxCreate = grpclib.client.UnaryUnaryMethod(
3643
3695
  channel,
3644
3696
  '/modal.client.ModalClient/PersistentSandboxCreate',
@@ -3837,6 +3889,18 @@ class ModalClientStub:
3837
3889
  modal_proto.api_pb2.SandboxGetResourceUsageRequest,
3838
3890
  modal_proto.api_pb2.SandboxGetResourceUsageResponse,
3839
3891
  )
3892
+ self.SandboxGetStats = grpclib.client.UnaryUnaryMethod(
3893
+ channel,
3894
+ '/modal.client.ModalClient/SandboxGetStats',
3895
+ modal_proto.api_pb2.SandboxGetStatsRequest,
3896
+ modal_proto.api_pb2.SandboxGetStatsResponse,
3897
+ )
3898
+ self.SandboxGetStatsV2 = grpclib.client.UnaryUnaryMethod(
3899
+ channel,
3900
+ '/modal.client.ModalClient/SandboxGetStatsV2',
3901
+ modal_proto.api_pb2.SandboxGetStatsRequest,
3902
+ modal_proto.api_pb2.SandboxGetStatsResponse,
3903
+ )
3840
3904
  self.SandboxGetTaskId = grpclib.client.UnaryUnaryMethod(
3841
3905
  channel,
3842
3906
  '/modal.client.ModalClient/SandboxGetTaskId',