modal 1.1.5.dev35__tar.gz → 1.3.1.dev20__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 (211) hide show
  1. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/PKG-INFO +11 -9
  2. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/README.md +5 -5
  3. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/__init__.py +4 -4
  4. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/__main__.py +4 -29
  5. modal-1.3.1.dev20/modal/_billing.py +84 -0
  6. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/_clustered_functions.py +1 -3
  7. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/_container_entrypoint.py +52 -249
  8. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/_functions.py +204 -198
  9. modal-1.3.1.dev20/modal/_grpc_client.py +191 -0
  10. modal-1.3.1.dev20/modal/_ipython.py +21 -0
  11. modal-1.3.1.dev20/modal/_load_context.py +106 -0
  12. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/_object.py +72 -21
  13. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/_output.py +55 -32
  14. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/_partial_function.py +31 -25
  15. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/_resolver.py +44 -57
  16. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/_runtime/container_io_manager.py +287 -179
  17. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/_runtime/container_io_manager.pyi +72 -90
  18. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/_runtime/gpu_memory_snapshot.py +24 -19
  19. modal-1.3.1.dev20/modal/_runtime/user_code_event_loop.py +80 -0
  20. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/_runtime/user_code_imports.py +251 -15
  21. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/_serialization.py +59 -2
  22. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/_traceback.py +4 -13
  23. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/_tunnel.py +16 -11
  24. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/_tunnel.pyi +25 -3
  25. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/_utils/async_utils.py +337 -10
  26. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/_utils/auth_token_manager.py +1 -4
  27. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/_utils/blob_utils.py +33 -22
  28. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/_utils/function_utils.py +47 -29
  29. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/_utils/grpc_testing.py +6 -3
  30. modal-1.3.1.dev20/modal/_utils/grpc_utils.py +450 -0
  31. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/_utils/mount_utils.py +26 -1
  32. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/_utils/name_utils.py +17 -3
  33. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/_utils/package_utils.py +0 -1
  34. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/_utils/rand_pb_testing.py +8 -1
  35. modal-1.3.1.dev20/modal/_utils/task_command_router_client.py +524 -0
  36. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/_vendor/cloudpickle.py +144 -48
  37. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/app.py +299 -109
  38. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/app.pyi +233 -56
  39. modal-1.3.1.dev20/modal/billing.py +5 -0
  40. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/builder/2025.06.txt +6 -3
  41. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/builder/PREVIEW.txt +2 -1
  42. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/builder/base-images.json +4 -2
  43. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/cli/_download.py +19 -3
  44. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/cli/cluster.py +4 -2
  45. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/cli/config.py +3 -1
  46. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/cli/container.py +10 -6
  47. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/cli/dict.py +5 -2
  48. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/cli/entry_point.py +26 -2
  49. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/cli/environment.py +6 -19
  50. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/cli/launch.py +1 -76
  51. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/cli/network_file_system.py +5 -20
  52. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/cli/programs/run_jupyter.py +1 -1
  53. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/cli/programs/vscode.py +1 -1
  54. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/cli/queues.py +5 -4
  55. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/cli/run.py +37 -198
  56. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/cli/secret.py +1 -2
  57. modal-1.3.1.dev20/modal/cli/shell.py +375 -0
  58. modal-1.3.1.dev20/modal/cli/token.py +108 -0
  59. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/cli/utils.py +1 -13
  60. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/cli/volume.py +11 -17
  61. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/client.py +16 -125
  62. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/client.pyi +94 -144
  63. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/cloud_bucket_mount.py +3 -1
  64. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/cloud_bucket_mount.pyi +4 -0
  65. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/cls.py +98 -105
  66. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/cls.pyi +8 -85
  67. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/config.py +26 -1
  68. modal-1.3.1.dev20/modal/container_process.py +472 -0
  69. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/container_process.pyi +99 -38
  70. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/dict.py +86 -75
  71. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/dict.pyi +109 -139
  72. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/environments.py +15 -27
  73. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/environments.pyi +5 -15
  74. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/exception.py +154 -16
  75. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/experimental/__init__.py +34 -38
  76. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/experimental/flash.py +167 -74
  77. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/experimental/flash.pyi +102 -47
  78. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/file_io.py +50 -92
  79. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/file_io.pyi +117 -89
  80. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/functions.pyi +71 -136
  81. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/image.py +126 -89
  82. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/image.pyi +55 -35
  83. modal-1.3.1.dev20/modal/io_streams.py +822 -0
  84. modal-1.3.1.dev20/modal/io_streams.pyi +530 -0
  85. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/mount.py +66 -164
  86. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/mount.pyi +33 -179
  87. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/network_file_system.py +20 -51
  88. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/network_file_system.pyi +53 -94
  89. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/object.pyi +114 -22
  90. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/output.py +2 -2
  91. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/parallel_map.py +44 -48
  92. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/parallel_map.pyi +9 -17
  93. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/partial_function.pyi +4 -3
  94. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/proxy.py +14 -6
  95. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/proxy.pyi +10 -2
  96. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/queue.py +44 -76
  97. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/queue.pyi +81 -119
  98. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/runner.py +111 -98
  99. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/runner.pyi +45 -27
  100. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/sandbox.py +231 -113
  101. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/sandbox.pyi +232 -66
  102. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/secret.py +57 -84
  103. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/secret.pyi +28 -51
  104. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/serving.py +7 -11
  105. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/serving.pyi +7 -8
  106. modal-1.3.1.dev20/modal/snapshot.py +56 -0
  107. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/snapshot.pyi +18 -10
  108. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/token_flow.py +1 -1
  109. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/token_flow.pyi +4 -6
  110. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/volume.py +102 -96
  111. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/volume.pyi +102 -120
  112. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal.egg-info/PKG-INFO +11 -9
  113. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal.egg-info/SOURCES.txt +13 -9
  114. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal.egg-info/requires.txt +8 -2
  115. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal_proto/api.proto +225 -58
  116. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal_proto/api_grpc.py +91 -10
  117. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal_proto/api_pb2.py +1242 -1074
  118. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal_proto/api_pb2.pyi +621 -54
  119. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal_proto/api_pb2_grpc.py +180 -16
  120. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal_proto/api_pb2_grpc.pyi +59 -11
  121. modal-1.3.1.dev20/modal_proto/modal_api_grpc.py +195 -0
  122. modal-1.3.1.dev20/modal_proto/task_command_router.proto +164 -0
  123. modal-1.3.1.dev20/modal_proto/task_command_router_grpc.py +138 -0
  124. modal-1.3.1.dev20/modal_proto/task_command_router_pb2.py +180 -0
  125. modal-1.3.1.dev20/modal_proto/task_command_router_pb2.pyi +384 -0
  126. modal-1.3.1.dev20/modal_proto/task_command_router_pb2_grpc.py +272 -0
  127. modal-1.3.1.dev20/modal_proto/task_command_router_pb2_grpc.pyi +100 -0
  128. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal_version/__init__.py +1 -1
  129. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal_version/__main__.py +1 -1
  130. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/pyproject.toml +36 -10
  131. modal-1.1.5.dev35/modal/_ipython.py +0 -11
  132. modal-1.1.5.dev35/modal/_utils/grpc_utils.py +0 -293
  133. modal-1.1.5.dev35/modal/cli/programs/launch_instance_ssh.py +0 -94
  134. modal-1.1.5.dev35/modal/cli/programs/run_marimo.py +0 -95
  135. modal-1.1.5.dev35/modal/cli/token.py +0 -60
  136. modal-1.1.5.dev35/modal/container_process.py +0 -196
  137. modal-1.1.5.dev35/modal/io_streams.py +0 -471
  138. modal-1.1.5.dev35/modal/io_streams.pyi +0 -440
  139. modal-1.1.5.dev35/modal/snapshot.py +0 -42
  140. modal-1.1.5.dev35/modal_proto/modal_api_grpc.py +0 -190
  141. modal-1.1.5.dev35/modal_proto/modal_options_grpc.py +0 -3
  142. modal-1.1.5.dev35/modal_proto/options.proto +0 -19
  143. modal-1.1.5.dev35/modal_proto/options_grpc.py +0 -3
  144. modal-1.1.5.dev35/modal_proto/options_pb2.py +0 -35
  145. modal-1.1.5.dev35/modal_proto/options_pb2.pyi +0 -20
  146. modal-1.1.5.dev35/modal_proto/options_pb2_grpc.py +0 -4
  147. modal-1.1.5.dev35/modal_proto/options_pb2_grpc.pyi +0 -7
  148. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/LICENSE +0 -0
  149. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/_clustered_functions.pyi +0 -0
  150. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/_location.py +0 -0
  151. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/_pty.py +0 -0
  152. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/_resources.py +0 -0
  153. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/_runtime/__init__.py +0 -0
  154. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/_runtime/asgi.py +0 -0
  155. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/_runtime/execution_context.py +0 -0
  156. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/_runtime/execution_context.pyi +0 -0
  157. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/_runtime/telemetry.py +0 -0
  158. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/_type_manager.py +0 -0
  159. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/_utils/__init__.py +0 -0
  160. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/_utils/app_utils.py +0 -0
  161. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/_utils/bytes_io_segment_payload.py +0 -0
  162. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/_utils/deprecation.py +0 -0
  163. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/_utils/docker_utils.py +0 -0
  164. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/_utils/git_utils.py +0 -0
  165. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/_utils/hash_utils.py +0 -0
  166. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/_utils/http_utils.py +0 -0
  167. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/_utils/jwt_utils.py +0 -0
  168. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/_utils/logger.py +0 -0
  169. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/_utils/pattern_utils.py +0 -0
  170. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/_utils/shell_utils.py +0 -0
  171. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/_utils/time_utils.py +0 -0
  172. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/_vendor/__init__.py +0 -0
  173. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/_vendor/a2wsgi_wsgi.py +0 -0
  174. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/_vendor/tblib.py +0 -0
  175. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/_watcher.py +0 -0
  176. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/builder/2023.12.312.txt +0 -0
  177. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/builder/2023.12.txt +0 -0
  178. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/builder/2024.04.txt +0 -0
  179. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/builder/2024.10.txt +0 -0
  180. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/builder/README.md +0 -0
  181. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/call_graph.py +0 -0
  182. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/cli/__init__.py +0 -0
  183. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/cli/_traceback.py +0 -0
  184. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/cli/app.py +0 -0
  185. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/cli/import_refs.py +0 -0
  186. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/cli/profile.py +0 -0
  187. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/cli/programs/__init__.py +0 -0
  188. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/experimental/ipython.py +0 -0
  189. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/file_pattern_matcher.py +0 -0
  190. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/functions.py +0 -0
  191. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/gpu.py +0 -0
  192. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/object.py +0 -0
  193. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/partial_function.py +0 -0
  194. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/py.typed +0 -0
  195. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/retries.py +0 -0
  196. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/running_app.py +0 -0
  197. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/schedule.py +0 -0
  198. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/scheduler_placement.py +0 -0
  199. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal/stream_type.py +0 -0
  200. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal.egg-info/dependency_links.txt +0 -0
  201. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal.egg-info/entry_points.txt +0 -0
  202. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal.egg-info/top_level.txt +0 -0
  203. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal_docs/__init__.py +0 -0
  204. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal_docs/gen_cli_docs.py +0 -0
  205. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal_docs/gen_reference_docs.py +0 -0
  206. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal_docs/mdmd/__init__.py +0 -0
  207. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal_docs/mdmd/mdmd.py +0 -0
  208. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal_docs/mdmd/signatures.py +0 -0
  209. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal_proto/__init__.py +0 -0
  210. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/modal_proto/py.typed +0 -0
  211. {modal-1.1.5.dev35 → modal-1.3.1.dev20}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.1.5.dev35
3
+ Version: 1.3.1.dev20
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License: Apache-2.0
@@ -13,16 +13,18 @@ Classifier: Topic :: System :: Distributed Computing
13
13
  Classifier: Operating System :: OS Independent
14
14
  Classifier: License :: OSI Approved :: Apache Software License
15
15
  Classifier: Programming Language :: Python :: 3
16
- Requires-Python: >=3.9
16
+ Requires-Python: <3.15,>=3.10
17
17
  Description-Content-Type: text/markdown
18
18
  License-File: LICENSE
19
19
  Requires-Dist: aiohttp
20
+ Requires-Dist: cbor2
20
21
  Requires-Dist: certifi
21
22
  Requires-Dist: click~=8.1
22
- Requires-Dist: grpclib<0.4.9,>=0.4.7
23
+ Requires-Dist: grpclib<0.4.10,>=0.4.7; python_version < "3.14"
24
+ Requires-Dist: grpclib<0.4.10,>=0.4.9; python_version >= "3.14"
23
25
  Requires-Dist: protobuf!=4.24.0,<7.0,>=3.19
24
26
  Requires-Dist: rich>=12.0.0
25
- Requires-Dist: synchronicity~=0.10.2
27
+ Requires-Dist: synchronicity~=0.11.1
26
28
  Requires-Dist: toml
27
29
  Requires-Dist: typer>=0.9
28
30
  Requires-Dist: types-certifi
@@ -31,14 +33,14 @@ Requires-Dist: watchfiles
31
33
  Requires-Dist: typing_extensions~=4.6
32
34
  Dynamic: license-file
33
35
 
34
- # Modal Python Library
36
+ # Modal Python SDK
35
37
 
36
38
  [![PyPI Version](https://img.shields.io/pypi/v/modal.svg)](https://pypi.org/project/modal/)
37
39
  [![License](https://img.shields.io/badge/license-apache_2.0-darkviolet.svg)](https://github.com/modal-labs/modal-client/blob/master/LICENSE)
38
40
  [![Tests](https://github.com/modal-labs/modal-client/actions/workflows/ci-cd.yml/badge.svg)](https://github.com/modal-labs/modal-client/actions/workflows/ci-cd.yml)
39
41
  [![Slack](https://img.shields.io/badge/slack-join-blue.svg?logo=slack)](https://modal.com/slack)
40
42
 
41
- The [Modal](https://modal.com/) Python library provides convenient, on-demand
43
+ The [Modal](https://modal.com/) Python SDK provides convenient, on-demand
42
44
  access to serverless cloud compute from Python scripts on your local computer.
43
45
 
44
46
  ## Documentation
@@ -50,12 +52,12 @@ a [user guide](https://modal.com/docs/guide), and the detailed
50
52
 
51
53
  ## Installation
52
54
 
53
- **This library requires Python 3.9 – 3.13.**
55
+ **This library requires Python 3.10 – 3.14.**
54
56
 
55
- Install the package with `pip`:
57
+ Install the package with `uv` or `pip`:
56
58
 
57
59
  ```bash
58
- pip install modal
60
+ uv pip install modal
59
61
  ```
60
62
 
61
63
  You can create a Modal account (or link your existing one) directly on the
@@ -1,11 +1,11 @@
1
- # Modal Python Library
1
+ # Modal Python SDK
2
2
 
3
3
  [![PyPI Version](https://img.shields.io/pypi/v/modal.svg)](https://pypi.org/project/modal/)
4
4
  [![License](https://img.shields.io/badge/license-apache_2.0-darkviolet.svg)](https://github.com/modal-labs/modal-client/blob/master/LICENSE)
5
5
  [![Tests](https://github.com/modal-labs/modal-client/actions/workflows/ci-cd.yml/badge.svg)](https://github.com/modal-labs/modal-client/actions/workflows/ci-cd.yml)
6
6
  [![Slack](https://img.shields.io/badge/slack-join-blue.svg?logo=slack)](https://modal.com/slack)
7
7
 
8
- The [Modal](https://modal.com/) Python library provides convenient, on-demand
8
+ The [Modal](https://modal.com/) Python SDK provides convenient, on-demand
9
9
  access to serverless cloud compute from Python scripts on your local computer.
10
10
 
11
11
  ## Documentation
@@ -17,12 +17,12 @@ a [user guide](https://modal.com/docs/guide), and the detailed
17
17
 
18
18
  ## Installation
19
19
 
20
- **This library requires Python 3.9 – 3.13.**
20
+ **This library requires Python 3.10 – 3.14.**
21
21
 
22
- Install the package with `pip`:
22
+ Install the package with `uv` or `pip`:
23
23
 
24
24
  ```bash
25
- pip install modal
25
+ uv pip install modal
26
26
  ```
27
27
 
28
28
  You can create a Modal account (or link your existing one) directly on the
@@ -1,10 +1,10 @@
1
1
  # Copyright Modal Labs 2022
2
2
  import sys
3
3
 
4
- if sys.version_info[:2] < (3, 9):
5
- raise RuntimeError("This version of Modal requires at least Python 3.9")
6
- if sys.version_info[:2] >= (3, 14):
7
- raise RuntimeError("This version of Modal does not support Python 3.14+")
4
+ if sys.version_info[:2] < (3, 10):
5
+ raise RuntimeError("This version of Modal requires at least Python 3.10")
6
+ if sys.version_info[:2] >= (3, 15):
7
+ raise RuntimeError("This version of Modal does not support Python 3.15+")
8
8
 
9
9
  from modal_version import __version__
10
10
 
@@ -35,37 +35,12 @@ def main():
35
35
  ):
36
36
  raise
37
37
 
38
- from grpclib import GRPCError, Status
39
38
  from rich.panel import Panel
40
39
 
41
- if isinstance(exc, GRPCError):
42
- status_map = {
43
- Status.ABORTED: "Aborted",
44
- Status.ALREADY_EXISTS: "Already exists",
45
- Status.CANCELLED: "Cancelled",
46
- Status.DATA_LOSS: "Data loss",
47
- Status.DEADLINE_EXCEEDED: "Deadline exceeded",
48
- Status.FAILED_PRECONDITION: "Failed precondition",
49
- Status.INTERNAL: "Internal",
50
- Status.INVALID_ARGUMENT: "Invalid",
51
- Status.NOT_FOUND: "Not found",
52
- Status.OUT_OF_RANGE: "Out of range",
53
- Status.PERMISSION_DENIED: "Permission denied",
54
- Status.RESOURCE_EXHAUSTED: "Resource exhausted",
55
- Status.UNAUTHENTICATED: "Unauthenticaed",
56
- Status.UNAVAILABLE: "Unavailable",
57
- Status.UNIMPLEMENTED: "Unimplemented",
58
- Status.UNKNOWN: "Unknown",
59
- }
60
- title = f"Error: {status_map.get(exc.status, 'Unknown')}"
61
- content = str(exc.message)
62
- if exc.details:
63
- content += f"\n\nDetails: {exc.details}"
64
- else:
65
- title = "Error"
66
- content = str(exc)
67
- if notes := getattr(exc, "__notes__", []):
68
- content = f"{content}\n\nNote: {' '.join(notes)}"
40
+ title = "Error"
41
+ content = str(exc)
42
+ if notes := getattr(exc, "__notes__", []):
43
+ content = f"{content}\n\nNote: {' '.join(notes)}"
69
44
 
70
45
  console = make_console(stderr=True)
71
46
  panel = Panel(content, title=title, title_align="left", border_style="red")
@@ -0,0 +1,84 @@
1
+ # Copyright Modal Labs 2025
2
+ from datetime import datetime, timezone
3
+ from decimal import Decimal
4
+ from typing import Any, Optional, TypedDict
5
+
6
+ from modal_proto import api_pb2
7
+
8
+ from .client import _Client
9
+ from .exception import InvalidError
10
+
11
+
12
+ class WorkspaceBillingReportItem(TypedDict):
13
+ object_id: str
14
+ description: str
15
+ environment_name: str
16
+ interval_start: datetime
17
+ cost: Decimal
18
+ tags: dict[str, str]
19
+
20
+
21
+ async def _workspace_billing_report(
22
+ *,
23
+ start: datetime, # Start of the report, inclusive
24
+ end: Optional[datetime] = None, # End of the report, exclusive
25
+ resolution: str = "d", # Resolution, e.g. "d" for daily or "h" for hourly
26
+ tag_names: Optional[list[str]] = None, # Optional additional metadata to include
27
+ client: Optional[_Client] = None,
28
+ ) -> list[dict[str, Any]]:
29
+ """Generate a tabular report of workspace usage by object and time.
30
+
31
+ The result will be a list of dictionaries for each interval (determined by `resolution`)
32
+ between the `start` and `end` limits. The dictionary represents a single Modal object
33
+ that billing can be attributed to (e.g., an App) along with metadata (including user-defined
34
+ tags) for identifying that object.
35
+
36
+ The `start` and `end` parameters are required to either have a UTC timezone or to be
37
+ timezone-naive (which will be interpreted as UTC times). The timestamps in the result will
38
+ be in UTC. Cost will be reported for full intervals, even if the provided `start` or `end`
39
+ parameters are partial: `start` will be rounded to the beginning of its interval, while
40
+ partial `end` intervals will be excluded.
41
+
42
+ Additional user-provided metadata can be included in the report if the objects have tags
43
+ and `tag_names` (i.e., keys) are specified in the request. Note that tags will be attributed
44
+ to the entire interval even if they were added or removed at some point within it.
45
+
46
+ """
47
+ if client is None:
48
+ client = await _Client.from_env()
49
+
50
+ tag_names = tag_names or []
51
+
52
+ if end is None:
53
+ end = datetime.now(timezone.utc)
54
+
55
+ if start.tzinfo is None:
56
+ start = start.replace(tzinfo=timezone.utc)
57
+ elif start.tzinfo != timezone.utc:
58
+ raise InvalidError("Timezone-aware 'start' parameter must be in UTC.")
59
+
60
+ if end.tzinfo is None:
61
+ end = end.replace(tzinfo=timezone.utc)
62
+ elif end.tzinfo != timezone.utc:
63
+ raise InvalidError("Timezone-aware 'end' parameter must be in UTC.")
64
+
65
+ request = api_pb2.WorkspaceBillingReportRequest(
66
+ resolution=resolution,
67
+ tag_names=tag_names,
68
+ )
69
+ request.start_timestamp.FromDatetime(start)
70
+ request.end_timestamp.FromDatetime(end)
71
+
72
+ rows = []
73
+ async for pb_item in client.stub.WorkspaceBillingReport.unary_stream(request):
74
+ item = {
75
+ "object_id": pb_item.object_id,
76
+ "description": pb_item.description,
77
+ "environment_name": pb_item.environment_name,
78
+ "interval_start": pb_item.interval.ToDatetime().replace(tzinfo=timezone.utc),
79
+ "cost": Decimal(pb_item.cost),
80
+ "tags": dict(pb_item.tags),
81
+ }
82
+ rows.append(item)
83
+
84
+ return rows
@@ -5,7 +5,6 @@ from dataclasses import dataclass
5
5
  from typing import Optional
6
6
 
7
7
  from modal._utils.async_utils import synchronize_api
8
- from modal._utils.grpc_utils import retry_transient_errors
9
8
  from modal.client import _Client
10
9
  from modal.exception import InvalidError
11
10
  from modal_proto import api_pb2
@@ -61,8 +60,7 @@ async def _initialize_clustered_function(client: _Client, task_id: str, world_si
61
60
  os.environ["NCCL_NSOCKS_PERTHREAD"] = "1"
62
61
 
63
62
  if world_size > 1:
64
- resp: api_pb2.TaskClusterHelloResponse = await retry_transient_errors(
65
- client.stub.TaskClusterHello,
63
+ resp = await client.stub.TaskClusterHello(
66
64
  api_pb2.TaskClusterHelloRequest(
67
65
  task_id=task_id,
68
66
  container_ip=container_ip,