modAL 1.3.2.dev0__tar.gz → 1.3.3.dev0__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 (201) hide show
  1. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/PKG-INFO +1 -1
  2. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_object.py +40 -35
  3. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_output.py +2 -1
  4. modal-1.3.3.dev0/modal/_utils/browser_utils.py +28 -0
  5. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/app.pyi +3 -3
  6. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/cli/_download.py +2 -0
  7. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/cli/app.py +34 -0
  8. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/cli/container.py +9 -1
  9. modal-1.3.3.dev0/modal/cli/dashboard.py +30 -0
  10. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/cli/entry_point.py +3 -1
  11. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/cli/utils.py +4 -2
  12. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/cli/volume.py +28 -0
  13. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/client.pyi +2 -2
  14. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/config.py +1 -1
  15. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/functions.pyi +6 -6
  16. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/image.pyi +1 -1
  17. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/object.pyi +24 -57
  18. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/partial_function.pyi +1 -2
  19. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/runner.py +1 -5
  20. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/token_flow.py +2 -17
  21. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/token_flow.pyi +0 -3
  22. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/volume.py +11 -4
  23. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/volume.pyi +3 -0
  24. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal.egg-info/PKG-INFO +1 -1
  25. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal.egg-info/SOURCES.txt +2 -0
  26. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal_docs/gen_reference_docs.py +1 -1
  27. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal_proto/api.proto +10 -0
  28. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal_proto/api_grpc.py +16 -0
  29. modal-1.3.3.dev0/modal_proto/api_pb2.py +1139 -0
  30. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal_proto/api_pb2.pyi +28 -0
  31. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal_proto/api_pb2_grpc.py +33 -0
  32. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal_proto/api_pb2_grpc.pyi +10 -0
  33. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal_proto/modal_api_grpc.py +1 -0
  34. modal-1.3.3.dev0/modal_proto/task_command_router_pb2.py +60 -0
  35. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal_version/__init__.py +1 -1
  36. modal-1.3.2.dev0/modal_proto/api_pb2.py +0 -5230
  37. modal-1.3.2.dev0/modal_proto/task_command_router_pb2.py +0 -180
  38. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/LICENSE +0 -0
  39. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/README.md +0 -0
  40. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/__init__.py +0 -0
  41. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/__main__.py +0 -0
  42. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_billing.py +0 -0
  43. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_clustered_functions.py +0 -0
  44. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_clustered_functions.pyi +0 -0
  45. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_container_entrypoint.py +0 -0
  46. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_functions.py +0 -0
  47. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_grpc_client.py +0 -0
  48. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_ipython.py +0 -0
  49. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_load_context.py +0 -0
  50. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_location.py +0 -0
  51. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_partial_function.py +0 -0
  52. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_pty.py +0 -0
  53. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_resolver.py +0 -0
  54. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_resources.py +0 -0
  55. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_runtime/__init__.py +0 -0
  56. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_runtime/asgi.py +0 -0
  57. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_runtime/container_io_manager.py +0 -0
  58. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_runtime/container_io_manager.pyi +0 -0
  59. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_runtime/execution_context.py +0 -0
  60. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_runtime/execution_context.pyi +0 -0
  61. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_runtime/gpu_memory_snapshot.py +0 -0
  62. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_runtime/telemetry.py +0 -0
  63. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_runtime/user_code_event_loop.py +0 -0
  64. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_runtime/user_code_imports.py +0 -0
  65. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_serialization.py +0 -0
  66. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_server.py +0 -0
  67. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_traceback.py +0 -0
  68. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_tunnel.py +0 -0
  69. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_tunnel.pyi +0 -0
  70. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_type_manager.py +0 -0
  71. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_utils/__init__.py +0 -0
  72. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_utils/app_utils.py +0 -0
  73. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_utils/async_utils.py +0 -0
  74. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_utils/auth_token_manager.py +0 -0
  75. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_utils/blob_utils.py +0 -0
  76. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_utils/bytes_io_segment_payload.py +0 -0
  77. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_utils/deprecation.py +0 -0
  78. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_utils/docker_utils.py +0 -0
  79. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_utils/function_utils.py +0 -0
  80. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_utils/git_utils.py +0 -0
  81. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_utils/grpc_testing.py +0 -0
  82. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_utils/grpc_utils.py +0 -0
  83. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_utils/hash_utils.py +0 -0
  84. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_utils/http_utils.py +0 -0
  85. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_utils/jwt_utils.py +0 -0
  86. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_utils/logger.py +0 -0
  87. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_utils/mount_utils.py +0 -0
  88. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_utils/name_utils.py +0 -0
  89. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_utils/package_utils.py +0 -0
  90. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_utils/pattern_utils.py +0 -0
  91. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_utils/rand_pb_testing.py +0 -0
  92. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_utils/shell_utils.py +0 -0
  93. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_utils/task_command_router_client.py +0 -0
  94. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_utils/time_utils.py +0 -0
  95. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_vendor/__init__.py +0 -0
  96. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_vendor/a2wsgi_wsgi.py +0 -0
  97. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_vendor/cloudpickle.py +0 -0
  98. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_vendor/tblib.py +0 -0
  99. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/_watcher.py +0 -0
  100. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/app.py +0 -0
  101. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/billing.py +0 -0
  102. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/builder/2023.12.312.txt +0 -0
  103. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/builder/2023.12.txt +0 -0
  104. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/builder/2024.04.txt +0 -0
  105. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/builder/2024.10.txt +0 -0
  106. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/builder/2025.06.txt +0 -0
  107. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/builder/PREVIEW.txt +0 -0
  108. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/builder/README.md +0 -0
  109. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/builder/base-images.json +0 -0
  110. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/call_graph.py +0 -0
  111. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/cli/__init__.py +0 -0
  112. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/cli/_traceback.py +0 -0
  113. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/cli/cluster.py +0 -0
  114. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/cli/config.py +0 -0
  115. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/cli/dict.py +0 -0
  116. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/cli/environment.py +0 -0
  117. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/cli/import_refs.py +0 -0
  118. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/cli/launch.py +0 -0
  119. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/cli/network_file_system.py +0 -0
  120. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/cli/profile.py +0 -0
  121. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/cli/programs/__init__.py +0 -0
  122. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/cli/programs/run_jupyter.py +0 -0
  123. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/cli/programs/vscode.py +0 -0
  124. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/cli/queues.py +0 -0
  125. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/cli/run.py +0 -0
  126. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/cli/secret.py +0 -0
  127. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/cli/shell.py +0 -0
  128. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/cli/token.py +0 -0
  129. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/client.py +0 -0
  130. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/cloud_bucket_mount.py +0 -0
  131. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/cloud_bucket_mount.pyi +0 -0
  132. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/cls.py +0 -0
  133. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/cls.pyi +0 -0
  134. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/container_process.py +0 -0
  135. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/container_process.pyi +0 -0
  136. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/dict.py +0 -0
  137. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/dict.pyi +0 -0
  138. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/environments.py +0 -0
  139. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/environments.pyi +0 -0
  140. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/exception.py +0 -0
  141. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/experimental/__init__.py +0 -0
  142. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/experimental/flash.py +0 -0
  143. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/experimental/flash.pyi +0 -0
  144. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/experimental/ipython.py +0 -0
  145. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/file_io.py +0 -0
  146. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/file_io.pyi +0 -0
  147. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/file_pattern_matcher.py +0 -0
  148. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/functions.py +0 -0
  149. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/gpu.py +0 -0
  150. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/image.py +0 -0
  151. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/io_streams.py +0 -0
  152. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/io_streams.pyi +0 -0
  153. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/mount.py +0 -0
  154. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/mount.pyi +0 -0
  155. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/network_file_system.py +0 -0
  156. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/network_file_system.pyi +0 -0
  157. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/object.py +0 -0
  158. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/output.py +0 -0
  159. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/parallel_map.py +0 -0
  160. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/parallel_map.pyi +0 -0
  161. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/partial_function.py +0 -0
  162. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/proxy.py +0 -0
  163. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/proxy.pyi +0 -0
  164. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/py.typed +0 -0
  165. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/queue.py +0 -0
  166. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/queue.pyi +0 -0
  167. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/retries.py +0 -0
  168. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/runner.pyi +0 -0
  169. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/running_app.py +0 -0
  170. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/sandbox.py +0 -0
  171. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/sandbox.pyi +0 -0
  172. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/schedule.py +0 -0
  173. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/scheduler_placement.py +0 -0
  174. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/secret.py +0 -0
  175. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/secret.pyi +0 -0
  176. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/server.py +0 -0
  177. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/server.pyi +0 -0
  178. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/serving.py +0 -0
  179. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/serving.pyi +0 -0
  180. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/snapshot.py +0 -0
  181. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/snapshot.pyi +0 -0
  182. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal/stream_type.py +0 -0
  183. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal.egg-info/dependency_links.txt +0 -0
  184. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal.egg-info/entry_points.txt +0 -0
  185. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal.egg-info/requires.txt +0 -0
  186. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal.egg-info/top_level.txt +0 -0
  187. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal_docs/__init__.py +0 -0
  188. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal_docs/gen_cli_docs.py +0 -0
  189. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal_docs/mdmd/__init__.py +0 -0
  190. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal_docs/mdmd/mdmd.py +0 -0
  191. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal_docs/mdmd/signatures.py +0 -0
  192. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal_proto/__init__.py +0 -0
  193. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal_proto/py.typed +0 -0
  194. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal_proto/task_command_router.proto +0 -0
  195. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal_proto/task_command_router_grpc.py +0 -0
  196. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal_proto/task_command_router_pb2.pyi +0 -0
  197. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal_proto/task_command_router_pb2_grpc.py +0 -0
  198. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal_proto/task_command_router_pb2_grpc.pyi +0 -0
  199. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/modal_version/__main__.py +0 -0
  200. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/pyproject.toml +0 -0
  201. {modal-1.3.2.dev0 → modal-1.3.3.dev0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.3.2.dev0
3
+ Version: 1.3.3.dev0
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License: Apache-2.0
@@ -39,6 +39,41 @@ def _get_environment_name(
39
39
  return config.get("environment")
40
40
 
41
41
 
42
+ def live_method(method):
43
+ @wraps(method)
44
+ async def wrapped(self, *args, **kwargs):
45
+ await self.hydrate()
46
+ return await method(self, *args, **kwargs)
47
+
48
+ return wrapped
49
+
50
+
51
+ def live_method_gen(method):
52
+ @wraps(method)
53
+ async def wrapped(self, *args, **kwargs):
54
+ await self.hydrate()
55
+ async with aclosing(method(self, *args, **kwargs)) as stream:
56
+ async for item in stream:
57
+ yield item
58
+
59
+ return wrapped
60
+
61
+
62
+ def live_method_contextmanager(method):
63
+ # make sure a wrapped function returning an async context manager
64
+ # will not require both an `await func.aio()` and `async with`
65
+ # which would have been the case if it was wrapped in live_method
66
+
67
+ @wraps(method)
68
+ @contextlib.asynccontextmanager
69
+ async def wrapped(self, *args, **kwargs):
70
+ await self.hydrate()
71
+ async with method(self, *args, **kwargs) as ctx:
72
+ yield ctx
73
+
74
+ return wrapped
75
+
76
+
42
77
  class _Object:
43
78
  _type_prefix: ClassVar[Optional[str]] = None
44
79
  _prefix_to_type: ClassVar[dict[str, type]] = {}
@@ -275,6 +310,11 @@ class _Object:
275
310
  raise AttributeError(f"Attempting to get object_id of unhydrated {self}")
276
311
  return self._object_id
277
312
 
313
+ @live_method
314
+ async def get_dashboard_url(self) -> str:
315
+ """mdmd:hidden"""
316
+ return f"https://modal.com/id/{self.object_id}"
317
+
278
318
  @property
279
319
  def client(self) -> _Client:
280
320
  """mdmd:hidden"""
@@ -336,38 +376,3 @@ class _Object:
336
376
  with suppress_tb_frame(): # skip this frame by default
337
377
  await resolver.load(self, root_load_context)
338
378
  return self
339
-
340
-
341
- def live_method(method):
342
- @wraps(method)
343
- async def wrapped(self, *args, **kwargs):
344
- await self.hydrate()
345
- return await method(self, *args, **kwargs)
346
-
347
- return wrapped
348
-
349
-
350
- def live_method_gen(method):
351
- @wraps(method)
352
- async def wrapped(self, *args, **kwargs):
353
- await self.hydrate()
354
- async with aclosing(method(self, *args, **kwargs)) as stream:
355
- async for item in stream:
356
- yield item
357
-
358
- return wrapped
359
-
360
-
361
- def live_method_contextmanager(method):
362
- # make sure a wrapped function returning an async context manager
363
- # will not require both an `await func.aio()` and `async with`
364
- # which would have been the case if it was wrapped in live_method
365
-
366
- @wraps(method)
367
- @contextlib.asynccontextmanager
368
- async def wrapped(self, *args, **kwargs):
369
- await self.hydrate()
370
- async with method(self, *args, **kwargs) as ctx:
371
- yield ctx
372
-
373
- return wrapped
@@ -545,7 +545,7 @@ async def get_app_logs_loop(
545
545
  output_mgr: OutputManager,
546
546
  app_id: str | None = None,
547
547
  task_id: str | None = None,
548
- app_logs_url: str | None = None,
548
+ sandbox_id: str | None = None,
549
549
  ):
550
550
  last_log_batch_entry_id = ""
551
551
 
@@ -600,6 +600,7 @@ async def get_app_logs_loop(
600
600
  request = api_pb2.AppGetLogsRequest(
601
601
  app_id=app_id or "",
602
602
  task_id=task_id or "",
603
+ sandbox_id=sandbox_id or "",
603
604
  timeout=55,
604
605
  last_entry_id=last_log_batch_entry_id,
605
606
  )
@@ -0,0 +1,28 @@
1
+ # Copyright Modal Labs 2026
2
+ import webbrowser
3
+
4
+ from rich.console import Console
5
+
6
+
7
+ def open_url(url: str) -> bool:
8
+ """Opens url in web browser, making sure we use a modern one (not Lynx etc)"""
9
+ try:
10
+ browser = webbrowser.get()
11
+ # zpresto defines `BROWSER=open` by default on macOS, which causes `webbrowser` to return `GenericBrowser`.
12
+ if isinstance(browser, webbrowser.GenericBrowser) and browser.name != "open":
13
+ return False
14
+ else:
15
+ return browser.open_new_tab(url)
16
+ except webbrowser.Error:
17
+ return False
18
+
19
+
20
+ def open_url_and_display(url: str, target: str, console: Console) -> None:
21
+ """Open a URL in the web browser and display it to the user."""
22
+ if open_url(url):
23
+ console.print(f"Opening {target} in your web browser...")
24
+ console.print(f"[link={url}]{url}[/link]")
25
+ else:
26
+ console.print("[yellow]Could not open web browser automatically.[/yellow]")
27
+ console.print("Please open this URL in your browser:")
28
+ console.print(f"[link={url}]{url}[/link]")
@@ -309,7 +309,7 @@ class _App:
309
309
  environment_name: typing.Optional[str] = None,
310
310
  tag: str = "",
311
311
  client: typing.Optional[modal.client._Client] = None,
312
- ) -> typing_extensions.Self:
312
+ ) -> typing.Self:
313
313
  """Deploy the App so that it is available persistently.
314
314
 
315
315
  Deployed Apps will be available for lookup or web-based invocations until they are stopped.
@@ -625,7 +625,7 @@ class _App:
625
625
  """
626
626
  ...
627
627
 
628
- def include(self, /, other_app: _App, inherit_tags: bool = True) -> typing_extensions.Self:
628
+ def include(self, /, other_app: _App, inherit_tags: bool = True) -> typing.Self:
629
629
  """Include another App's objects in this one.
630
630
 
631
631
  Useful for splitting up Modal Apps across different self-contained files.
@@ -1347,7 +1347,7 @@ class App:
1347
1347
  """
1348
1348
  ...
1349
1349
 
1350
- def include(self, /, other_app: App, inherit_tags: bool = True) -> typing_extensions.Self:
1350
+ def include(self, /, other_app: App, inherit_tags: bool = True) -> typing.Self:
1351
1351
  """Include another App's objects in this one.
1352
1352
 
1353
1353
  Useful for splitting up Modal Apps across different self-contained files.
@@ -40,6 +40,7 @@ async def _volume_download(
40
40
  q: asyncio.Queue[tuple[Optional[Path], Optional[FileEntry]]] = asyncio.Queue()
41
41
  num_consumers = 1 if is_pipe else concurrency # concurrency limit for downloading files
42
42
  download_semaphore = asyncio.Semaphore(concurrency)
43
+ rpc_semaphore = asyncio.Semaphore(64) # Limit concurrent RPCs to avoid overwhelming server.
43
44
 
44
45
  async def producer():
45
46
  iterator: AsyncIterator[FileEntry]
@@ -101,6 +102,7 @@ async def _volume_download(
101
102
  path=entry.path,
102
103
  fileobj=fp,
103
104
  download_semaphore=download_semaphore,
105
+ rpc_semaphore=rpc_semaphore,
104
106
  progress_cb=file_progress_cb,
105
107
  )
106
108
  else:
@@ -10,7 +10,9 @@ from rich.text import Text
10
10
  from typer import Argument
11
11
 
12
12
  from modal._object import _get_environment_name
13
+ from modal._output import make_console
13
14
  from modal._utils.async_utils import synchronizer
15
+ from modal._utils.browser_utils import open_url_and_display
14
16
  from modal.client import _Client
15
17
  from modal.environments import ensure_env
16
18
  from modal_proto import api_pb2
@@ -248,3 +250,35 @@ async def history(
248
250
 
249
251
  if deployments_with_dirty_commit and not json:
250
252
  rich.print("* - repo had uncommitted changes")
253
+
254
+
255
+ @app_cli.command("dashboard", no_args_is_help=True)
256
+ @synchronizer.create_blocking
257
+ async def dashboard(
258
+ app_identifier: str = APP_IDENTIFIER,
259
+ *,
260
+ env: Optional[str] = ENV_OPTION,
261
+ ):
262
+ """Open an App's dashboard page in your web browser.
263
+
264
+ **Examples:**
265
+
266
+ Open dashboard for an app by name:
267
+
268
+ ```
269
+ modal app dashboard my-app
270
+ ```
271
+
272
+ Use a specified environment:
273
+
274
+ ```
275
+ modal app dashboard my-app --env dev
276
+ ```
277
+ """
278
+ client = await _Client.from_env()
279
+ app_id = await get_app_id.aio(app_identifier, env, client)
280
+
281
+ console = make_console()
282
+ url = f"https://modal.com/id/{app_id}"
283
+
284
+ open_url_and_display(url, "App dashboard", console)
@@ -13,6 +13,7 @@ from modal.client import _Client
13
13
  from modal.config import config
14
14
  from modal.container_process import _ContainerProcess
15
15
  from modal.environments import ensure_env
16
+ from modal.exception import InvalidError
16
17
  from modal.stream_type import StreamType
17
18
  from modal_proto import api_pb2
18
19
 
@@ -52,7 +53,14 @@ def logs(
52
53
  timestamps: bool = typer.Option(False, "--timestamps", help="Show timestamps for each log line"),
53
54
  ):
54
55
  """Show logs for a specific container, streaming while active."""
55
- stream_app_logs(task_id=container_id, show_timestamps=timestamps)
56
+ task_id, sandbox_id = None, None
57
+ if container_id.startswith("sb-"):
58
+ sandbox_id = container_id
59
+ elif container_id.startswith("ta-"):
60
+ task_id = container_id
61
+ else:
62
+ raise InvalidError(f"Invalid container ID: {container_id}")
63
+ stream_app_logs(task_id=task_id, sandbox_id=sandbox_id, show_timestamps=timestamps)
56
64
 
57
65
 
58
66
  @container_cli.command("exec")
@@ -0,0 +1,30 @@
1
+ # Copyright Modal Labs 2026
2
+ from typing import Optional
3
+
4
+ import typer
5
+
6
+ from modal._output import make_console
7
+ from modal._utils.async_utils import synchronizer
8
+ from modal._utils.browser_utils import open_url_and_display
9
+ from modal.client import _Client
10
+ from modal.config import config
11
+ from modal_proto import api_pb2
12
+
13
+
14
+ @synchronizer.create_blocking
15
+ async def dashboard(
16
+ object_id: Optional[str] = typer.Argument(None, help="Open a view for a specific object."),
17
+ ):
18
+ """Open the Modal Dashboard in a web browser."""
19
+ console = make_console()
20
+
21
+ if object_id:
22
+ url = f"https://modal.com/id/{object_id}"
23
+ else:
24
+ env = config.get("environment")
25
+ request = api_pb2.WorkspaceDashboardUrlRequest(environment_name=env)
26
+ client = await _Client.from_env()
27
+ response = await client.stub.WorkspaceDashboardUrlGet(request)
28
+ url = response.url
29
+
30
+ open_url_and_display(url, "dashboard", console)
@@ -13,6 +13,7 @@ from .app import app_cli
13
13
  from .cluster import cluster_cli
14
14
  from .config import config_cli
15
15
  from .container import container_cli
16
+ from .dashboard import dashboard
16
17
  from .dict import dict_cli
17
18
  from .environment import environment_cli
18
19
  from .launch import launch_cli
@@ -118,6 +119,7 @@ async def setup(profile: Optional[str] = None):
118
119
  entrypoint_cli_typer.command("deploy", no_args_is_help=True)(run.deploy)
119
120
  entrypoint_cli_typer.command("serve", no_args_is_help=True)(run.serve)
120
121
  entrypoint_cli_typer.command("shell")(shell_module.shell)
122
+ entrypoint_cli_typer.command("dashboard")(dashboard)
121
123
  entrypoint_cli_typer.add_typer(launch_cli)
122
124
 
123
125
  # Deployments
@@ -128,7 +130,7 @@ entrypoint_cli_typer.add_typer(cluster_cli, rich_help_panel="Deployments", hidde
128
130
 
129
131
  # Storage
130
132
  entrypoint_cli_typer.add_typer(dict_cli, rich_help_panel="Storage")
131
- entrypoint_cli_typer.add_typer(nfs_cli, rich_help_panel="Storage")
133
+ entrypoint_cli_typer.add_typer(nfs_cli, rich_help_panel="Storage", hidden=True)
132
134
  entrypoint_cli_typer.add_typer(secret_cli, rich_help_panel="Storage")
133
135
  entrypoint_cli_typer.add_typer(queue_cli, rich_help_panel="Storage")
134
136
  entrypoint_cli_typer.add_typer(volume_cli, rich_help_panel="Storage")
@@ -21,14 +21,16 @@ from ..exception import NotFoundError
21
21
  async def stream_app_logs(
22
22
  app_id: Optional[str] = None,
23
23
  task_id: Optional[str] = None,
24
+ sandbox_id: Optional[str] = None,
24
25
  app_logs_url: Optional[str] = None,
25
26
  show_timestamps: bool = False,
26
27
  ):
27
28
  client = await _Client.from_env()
28
- output_mgr = OutputManager(status_spinner_text=f"Tailing logs for {app_id}", show_timestamps=show_timestamps)
29
+ display_id = app_id or task_id or sandbox_id
30
+ output_mgr = OutputManager(status_spinner_text=f"Tailing logs for {display_id}", show_timestamps=show_timestamps)
29
31
  try:
30
32
  with output_mgr.show_status_spinner():
31
- await get_app_logs_loop(client, output_mgr, app_id=app_id, task_id=task_id, app_logs_url=app_logs_url)
33
+ await get_app_logs_loop(client, output_mgr, app_id=app_id, task_id=task_id, sandbox_id=sandbox_id)
32
34
  except asyncio.CancelledError:
33
35
  pass
34
36
  except KeyboardInterrupt:
@@ -12,6 +12,7 @@ from typer import Argument, Option, Typer
12
12
  import modal
13
13
  from modal._output import OutputManager, ProgressHandler, make_console
14
14
  from modal._utils.async_utils import synchronizer
15
+ from modal._utils.browser_utils import open_url_and_display
15
16
  from modal._utils.time_utils import timestamp_to_localized_str
16
17
  from modal.cli._download import _volume_download
17
18
  from modal.cli.utils import ENV_OPTION, YES_OPTION, display_table
@@ -310,3 +311,30 @@ async def rename(
310
311
  )
311
312
 
312
313
  await _Volume.rename(old_name, new_name, environment_name=env)
314
+
315
+
316
+ @volume_cli.command(
317
+ name="dashboard",
318
+ help="Open the Volume's dashboard page in your web browser.",
319
+ rich_help_panel="Management",
320
+ )
321
+ @synchronizer.create_blocking
322
+ async def dashboard(
323
+ volume_name: str = Argument(help="Name of the Volume to view in the dashboard."),
324
+ env: Optional[str] = ENV_OPTION,
325
+ ):
326
+ """Open a Volume's dashboard page in your web browser.
327
+
328
+ **Example:**
329
+
330
+ ```
331
+ modal volume dashboard my-volume
332
+ ```
333
+ """
334
+ env = ensure_env(env)
335
+ volume = await _Volume.from_name(volume_name, environment_name=env).hydrate()
336
+
337
+ console = make_console()
338
+ url = f"https://modal.com/id/{volume.object_id}"
339
+
340
+ open_url_and_display(url, "Volume dashboard", console)
@@ -35,7 +35,7 @@ class _Client:
35
35
  server_url: str,
36
36
  client_type: int,
37
37
  credentials: typing.Optional[tuple[str, str]],
38
- version: str = "1.3.2.dev0",
38
+ version: str = "1.3.3.dev0",
39
39
  ):
40
40
  """mdmd:hidden
41
41
  The Modal client object is not intended to be instantiated directly by users.
@@ -171,7 +171,7 @@ class Client:
171
171
  server_url: str,
172
172
  client_type: int,
173
173
  credentials: typing.Optional[tuple[str, str]],
174
- version: str = "1.3.2.dev0",
174
+ version: str = "1.3.3.dev0",
175
175
  ):
176
176
  """mdmd:hidden
177
177
  The Modal client object is not intended to be instantiated directly by users.
@@ -261,7 +261,7 @@ _SETTINGS = {
261
261
  ),
262
262
  "dev_suffix": _Setting("", transform=_enforce_suffix_rules),
263
263
  "max_throttle_wait": _Setting(None, transform=lambda x: int(x) if x else None),
264
- "async_warnings": _Setting(False, transform=_to_boolean), # Feature flag for async API warnings
264
+ "async_warnings": _Setting(True, transform=_to_boolean), # Activate synchronicity usage warnings
265
265
  }
266
266
 
267
267
 
@@ -408,7 +408,7 @@ class Function(
408
408
 
409
409
  _call_generator: ___call_generator_spec
410
410
 
411
- class __remote_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER]):
411
+ class __remote_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER]):
412
412
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> ReturnType_INNER:
413
413
  """Calls the function remotely, executing it with the given arguments and returning the execution's result."""
414
414
  ...
@@ -417,7 +417,7 @@ class Function(
417
417
  """Calls the function remotely, executing it with the given arguments and returning the execution's result."""
418
418
  ...
419
419
 
420
- remote: __remote_spec[modal._functions.ReturnType, modal._functions.P]
420
+ remote: __remote_spec[modal._functions.P, modal._functions.ReturnType]
421
421
 
422
422
  class __remote_gen_spec(typing_extensions.Protocol):
423
423
  def __call__(self, /, *args, **kwargs) -> typing.Generator[typing.Any, None, None]:
@@ -444,7 +444,7 @@ class Function(
444
444
  """
445
445
  ...
446
446
 
447
- class ___experimental_spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER]):
447
+ class ___experimental_spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER]):
448
448
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
449
449
  """[Experimental] Calls the function with the given arguments, without waiting for the results.
450
450
 
@@ -467,7 +467,7 @@ class Function(
467
467
  """
468
468
  ...
469
469
 
470
- _experimental_spawn: ___experimental_spawn_spec[modal._functions.ReturnType, modal._functions.P]
470
+ _experimental_spawn: ___experimental_spawn_spec[modal._functions.P, modal._functions.ReturnType]
471
471
 
472
472
  class ___spawn_map_inner_spec(typing_extensions.Protocol[P_INNER]):
473
473
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> None: ...
@@ -475,7 +475,7 @@ class Function(
475
475
 
476
476
  _spawn_map_inner: ___spawn_map_inner_spec[modal._functions.P]
477
477
 
478
- class __spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER]):
478
+ class __spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER]):
479
479
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
480
480
  """Calls the function with the given arguments, without waiting for the results.
481
481
 
@@ -496,7 +496,7 @@ class Function(
496
496
  """
497
497
  ...
498
498
 
499
- spawn: __spawn_spec[modal._functions.ReturnType, modal._functions.P]
499
+ spawn: __spawn_spec[modal._functions.P, modal._functions.ReturnType]
500
500
 
501
501
  def get_raw_f(self) -> collections.abc.Callable[..., typing.Any]:
502
502
  """Return the inner Python object wrapped by this Modal Function."""
@@ -1041,7 +1041,7 @@ class _Image(modal._object._Object):
1041
1041
  """
1042
1042
  ...
1043
1043
 
1044
- async def hydrate(self, client: typing.Optional[modal.client._Client] = None) -> typing_extensions.Self:
1044
+ async def hydrate(self, client: typing.Optional[modal.client._Client] = None) -> typing.Self:
1045
1045
  """mdmd:hidden"""
1046
1046
  ...
1047
1047
 
@@ -13,13 +13,13 @@ class Object:
13
13
  _prefix_to_type: typing.ClassVar[dict[str, type]]
14
14
  _load: typing.Optional[
15
15
  collections.abc.Callable[
16
- [typing_extensions.Self, modal._resolver.Resolver, modal._load_context.LoadContext, typing.Optional[str]],
16
+ [typing.Self, modal._resolver.Resolver, modal._load_context.LoadContext, typing.Optional[str]],
17
17
  collections.abc.Awaitable[None],
18
18
  ]
19
19
  ]
20
20
  _preload: typing.Optional[
21
21
  collections.abc.Callable[
22
- [typing_extensions.Self, modal._resolver.Resolver, modal._load_context.LoadContext, typing.Optional[str]],
22
+ [typing.Self, modal._resolver.Resolver, modal._load_context.LoadContext, typing.Optional[str]],
23
23
  collections.abc.Awaitable[None],
24
24
  ]
25
25
  ]
@@ -51,25 +51,13 @@ class Object:
51
51
  rep: str,
52
52
  load: typing.Optional[
53
53
  collections.abc.Callable[
54
- [
55
- typing_extensions.Self,
56
- modal._resolver.Resolver,
57
- modal._load_context.LoadContext,
58
- typing.Optional[str],
59
- ],
60
- None,
54
+ [typing.Self, modal._resolver.Resolver, modal._load_context.LoadContext, typing.Optional[str]], None
61
55
  ]
62
56
  ] = None,
63
57
  is_another_app: bool = False,
64
58
  preload: typing.Optional[
65
59
  collections.abc.Callable[
66
- [
67
- typing_extensions.Self,
68
- modal._resolver.Resolver,
69
- modal._load_context.LoadContext,
70
- typing.Optional[str],
71
- ],
72
- None,
60
+ [typing.Self, modal._resolver.Resolver, modal._load_context.LoadContext, typing.Optional[str]], None
73
61
  ]
74
62
  ] = None,
75
63
  hydrate_lazily: bool = False,
@@ -85,24 +73,14 @@ class Object:
85
73
  rep: str,
86
74
  load: typing.Optional[
87
75
  collections.abc.Callable[
88
- [
89
- typing_extensions.Self,
90
- modal._resolver.Resolver,
91
- modal._load_context.LoadContext,
92
- typing.Optional[str],
93
- ],
76
+ [typing.Self, modal._resolver.Resolver, modal._load_context.LoadContext, typing.Optional[str]],
94
77
  collections.abc.Awaitable[None],
95
78
  ]
96
79
  ] = None,
97
80
  is_another_app: bool = False,
98
81
  preload: typing.Optional[
99
82
  collections.abc.Callable[
100
- [
101
- typing_extensions.Self,
102
- modal._resolver.Resolver,
103
- modal._load_context.LoadContext,
104
- typing.Optional[str],
105
- ],
83
+ [typing.Self, modal._resolver.Resolver, modal._load_context.LoadContext, typing.Optional[str]],
106
84
  collections.abc.Awaitable[None],
107
85
  ]
108
86
  ] = None,
@@ -127,7 +105,7 @@ class Object:
127
105
  def _hydrate_metadata(self, metadata: typing.Optional[google.protobuf.message.Message]): ...
128
106
  def _get_metadata(self) -> typing.Optional[google.protobuf.message.Message]: ...
129
107
  def _validate_is_hydrated(self): ...
130
- def clone(self) -> typing_extensions.Self:
108
+ def clone(self) -> typing.Self:
131
109
  """mdmd:hidden Clone a given hydrated object.
132
110
 
133
111
  Note: This is not intended to be public API and has no public use. It will be removed in a future release.
@@ -139,25 +117,13 @@ class Object:
139
117
  self,
140
118
  /,
141
119
  load: collections.abc.Callable[
142
- [
143
- typing_extensions.Self,
144
- modal._resolver.Resolver,
145
- modal._load_context.LoadContext,
146
- typing.Optional[str],
147
- ],
148
- None,
120
+ [typing.Self, modal._resolver.Resolver, modal._load_context.LoadContext, typing.Optional[str]], None
149
121
  ],
150
122
  rep: str,
151
123
  is_another_app: bool = False,
152
124
  preload: typing.Optional[
153
125
  collections.abc.Callable[
154
- [
155
- typing_extensions.Self,
156
- modal._resolver.Resolver,
157
- modal._load_context.LoadContext,
158
- typing.Optional[str],
159
- ],
160
- None,
126
+ [typing.Self, modal._resolver.Resolver, modal._load_context.LoadContext, typing.Optional[str]], None
161
127
  ]
162
128
  ] = None,
163
129
  hydrate_lazily: bool = False,
@@ -171,24 +137,14 @@ class Object:
171
137
  self,
172
138
  /,
173
139
  load: collections.abc.Callable[
174
- [
175
- typing_extensions.Self,
176
- modal._resolver.Resolver,
177
- modal._load_context.LoadContext,
178
- typing.Optional[str],
179
- ],
140
+ [typing.Self, modal._resolver.Resolver, modal._load_context.LoadContext, typing.Optional[str]],
180
141
  collections.abc.Awaitable[None],
181
142
  ],
182
143
  rep: str,
183
144
  is_another_app: bool = False,
184
145
  preload: typing.Optional[
185
146
  collections.abc.Callable[
186
- [
187
- typing_extensions.Self,
188
- modal._resolver.Resolver,
189
- modal._load_context.LoadContext,
190
- typing.Optional[str],
191
- ],
147
+ [typing.Self, modal._resolver.Resolver, modal._load_context.LoadContext, typing.Optional[str]],
192
148
  collections.abc.Awaitable[None],
193
149
  ]
194
150
  ] = None,
@@ -218,8 +174,8 @@ class Object:
218
174
  handle_metadata: typing.Optional[google.protobuf.message.Message],
219
175
  is_another_app: bool = False,
220
176
  rep: typing.Optional[str] = None,
221
- ) -> typing_extensions.Self: ...
222
- def _hydrate_from_other(self, other: typing_extensions.Self): ...
177
+ ) -> typing.Self: ...
178
+ def _hydrate_from_other(self, other: typing.Self): ...
223
179
  def __repr__(self): ...
224
180
  @property
225
181
  def local_uuid(self):
@@ -231,6 +187,17 @@ class Object:
231
187
  """mdmd:hidden"""
232
188
  ...
233
189
 
190
+ class __get_dashboard_url_spec(typing_extensions.Protocol):
191
+ def __call__(self, /) -> str:
192
+ """mdmd:hidden"""
193
+ ...
194
+
195
+ async def aio(self, /) -> str:
196
+ """mdmd:hidden"""
197
+ ...
198
+
199
+ get_dashboard_url: __get_dashboard_url_spec
200
+
234
201
  @property
235
202
  def client(self) -> modal.client.Client:
236
203
  """mdmd:hidden"""
@@ -2,7 +2,6 @@ import collections.abc
2
2
  import modal._partial_function
3
3
  import modal.functions
4
4
  import typing
5
- import typing_extensions
6
5
 
7
6
  class PartialFunction(
8
7
  typing.Generic[
@@ -31,7 +30,7 @@ class PartialFunction(
31
30
  self,
32
31
  flags: modal._partial_function._PartialFunctionFlags,
33
32
  params: modal._partial_function._PartialFunctionParams,
34
- ) -> typing_extensions.Self:
33
+ ) -> typing.Self:
35
34
  """Implement decorator composition by combining the flags and params."""
36
35
  ...
37
36
 
@@ -340,11 +340,7 @@ async def _run_app(
340
340
 
341
341
  # Start logs loop
342
342
 
343
- logs_loop = tc.create_task(
344
- get_app_logs_loop(
345
- load_context.client, output_mgr, app_id=running_app.app_id, app_logs_url=running_app.app_logs_url
346
- )
347
- )
343
+ logs_loop = tc.create_task(get_app_logs_loop(load_context.client, output_mgr, app_id=running_app.app_id))
348
344
 
349
345
  try:
350
346
  # Create all members