modal 1.1.1.dev25__tar.gz → 1.1.1.dev27__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.

Potentially problematic release.


This version of modal might be problematic. Click here for more details.

Files changed (188) hide show
  1. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/PKG-INFO +1 -1
  2. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/__main__.py +2 -2
  3. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/_output.py +12 -23
  4. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/cli/_traceback.py +3 -2
  5. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/cli/cluster.py +2 -2
  6. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/cli/config.py +2 -2
  7. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/cli/dict.py +2 -2
  8. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/cli/entry_point.py +2 -2
  9. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/cli/import_refs.py +3 -3
  10. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/cli/network_file_system.py +6 -7
  11. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/cli/profile.py +2 -2
  12. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/cli/queues.py +3 -3
  13. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/cli/secret.py +2 -2
  14. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/cli/utils.py +3 -4
  15. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/cli/volume.py +5 -6
  16. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/client.pyi +2 -2
  17. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/container_process.py +2 -2
  18. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/functions.pyi +6 -6
  19. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/token_flow.py +3 -3
  20. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal.egg-info/PKG-INFO +1 -1
  21. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal_version/__init__.py +1 -1
  22. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/LICENSE +0 -0
  23. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/README.md +0 -0
  24. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/__init__.py +0 -0
  25. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/_clustered_functions.py +0 -0
  26. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/_clustered_functions.pyi +0 -0
  27. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/_container_entrypoint.py +0 -0
  28. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/_functions.py +0 -0
  29. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/_ipython.py +0 -0
  30. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/_location.py +0 -0
  31. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/_object.py +0 -0
  32. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/_partial_function.py +0 -0
  33. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/_pty.py +0 -0
  34. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/_resolver.py +0 -0
  35. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/_resources.py +0 -0
  36. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/_runtime/__init__.py +0 -0
  37. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/_runtime/asgi.py +0 -0
  38. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/_runtime/container_io_manager.py +0 -0
  39. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/_runtime/container_io_manager.pyi +0 -0
  40. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/_runtime/execution_context.py +0 -0
  41. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/_runtime/execution_context.pyi +0 -0
  42. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/_runtime/gpu_memory_snapshot.py +0 -0
  43. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/_runtime/telemetry.py +0 -0
  44. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/_runtime/user_code_imports.py +0 -0
  45. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/_serialization.py +0 -0
  46. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/_traceback.py +0 -0
  47. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/_tunnel.py +0 -0
  48. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/_tunnel.pyi +0 -0
  49. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/_type_manager.py +0 -0
  50. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/_utils/__init__.py +0 -0
  51. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/_utils/app_utils.py +0 -0
  52. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/_utils/async_utils.py +0 -0
  53. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/_utils/auth_token_manager.py +0 -0
  54. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/_utils/blob_utils.py +0 -0
  55. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/_utils/bytes_io_segment_payload.py +0 -0
  56. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/_utils/deprecation.py +0 -0
  57. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/_utils/docker_utils.py +0 -0
  58. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/_utils/function_utils.py +0 -0
  59. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/_utils/git_utils.py +0 -0
  60. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/_utils/grpc_testing.py +0 -0
  61. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/_utils/grpc_utils.py +0 -0
  62. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/_utils/hash_utils.py +0 -0
  63. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/_utils/http_utils.py +0 -0
  64. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/_utils/jwt_utils.py +0 -0
  65. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/_utils/logger.py +0 -0
  66. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/_utils/mount_utils.py +0 -0
  67. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/_utils/name_utils.py +0 -0
  68. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/_utils/package_utils.py +0 -0
  69. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/_utils/pattern_utils.py +0 -0
  70. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/_utils/rand_pb_testing.py +0 -0
  71. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/_utils/shell_utils.py +0 -0
  72. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/_utils/time_utils.py +0 -0
  73. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/_vendor/__init__.py +0 -0
  74. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/_vendor/a2wsgi_wsgi.py +0 -0
  75. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/_vendor/cloudpickle.py +0 -0
  76. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/_vendor/tblib.py +0 -0
  77. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/_watcher.py +0 -0
  78. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/app.py +0 -0
  79. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/app.pyi +0 -0
  80. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/builder/2023.12.312.txt +0 -0
  81. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/builder/2023.12.txt +0 -0
  82. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/builder/2024.04.txt +0 -0
  83. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/builder/2024.10.txt +0 -0
  84. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/builder/2025.06.txt +0 -0
  85. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/builder/PREVIEW.txt +0 -0
  86. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/builder/README.md +0 -0
  87. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/builder/base-images.json +0 -0
  88. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/call_graph.py +0 -0
  89. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/cli/__init__.py +0 -0
  90. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/cli/_download.py +0 -0
  91. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/cli/app.py +0 -0
  92. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/cli/container.py +0 -0
  93. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/cli/environment.py +0 -0
  94. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/cli/launch.py +0 -0
  95. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/cli/programs/__init__.py +0 -0
  96. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/cli/programs/run_jupyter.py +0 -0
  97. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/cli/programs/vscode.py +0 -0
  98. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/cli/run.py +0 -0
  99. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/cli/token.py +0 -0
  100. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/client.py +0 -0
  101. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/cloud_bucket_mount.py +0 -0
  102. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/cloud_bucket_mount.pyi +0 -0
  103. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/cls.py +0 -0
  104. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/cls.pyi +0 -0
  105. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/config.py +0 -0
  106. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/container_process.pyi +0 -0
  107. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/dict.py +0 -0
  108. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/dict.pyi +0 -0
  109. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/environments.py +0 -0
  110. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/environments.pyi +0 -0
  111. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/exception.py +0 -0
  112. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/experimental/__init__.py +0 -0
  113. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/experimental/flash.py +0 -0
  114. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/experimental/flash.pyi +0 -0
  115. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/experimental/ipython.py +0 -0
  116. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/file_io.py +0 -0
  117. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/file_io.pyi +0 -0
  118. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/file_pattern_matcher.py +0 -0
  119. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/functions.py +0 -0
  120. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/gpu.py +0 -0
  121. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/image.py +0 -0
  122. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/image.pyi +0 -0
  123. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/io_streams.py +0 -0
  124. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/io_streams.pyi +0 -0
  125. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/mount.py +0 -0
  126. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/mount.pyi +0 -0
  127. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/network_file_system.py +0 -0
  128. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/network_file_system.pyi +0 -0
  129. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/object.py +0 -0
  130. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/object.pyi +0 -0
  131. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/output.py +0 -0
  132. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/parallel_map.py +0 -0
  133. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/parallel_map.pyi +0 -0
  134. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/partial_function.py +0 -0
  135. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/partial_function.pyi +0 -0
  136. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/proxy.py +0 -0
  137. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/proxy.pyi +0 -0
  138. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/py.typed +0 -0
  139. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/queue.py +0 -0
  140. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/queue.pyi +0 -0
  141. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/retries.py +0 -0
  142. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/runner.py +0 -0
  143. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/runner.pyi +0 -0
  144. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/running_app.py +0 -0
  145. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/sandbox.py +0 -0
  146. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/sandbox.pyi +0 -0
  147. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/schedule.py +0 -0
  148. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/scheduler_placement.py +0 -0
  149. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/secret.py +0 -0
  150. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/secret.pyi +0 -0
  151. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/serving.py +0 -0
  152. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/serving.pyi +0 -0
  153. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/snapshot.py +0 -0
  154. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/snapshot.pyi +0 -0
  155. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/stream_type.py +0 -0
  156. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/token_flow.pyi +0 -0
  157. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/volume.py +0 -0
  158. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal/volume.pyi +0 -0
  159. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal.egg-info/SOURCES.txt +0 -0
  160. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal.egg-info/dependency_links.txt +0 -0
  161. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal.egg-info/entry_points.txt +0 -0
  162. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal.egg-info/requires.txt +0 -0
  163. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal.egg-info/top_level.txt +0 -0
  164. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal_docs/__init__.py +0 -0
  165. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal_docs/gen_cli_docs.py +0 -0
  166. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal_docs/gen_reference_docs.py +0 -0
  167. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal_docs/mdmd/__init__.py +0 -0
  168. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal_docs/mdmd/mdmd.py +0 -0
  169. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal_docs/mdmd/signatures.py +0 -0
  170. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal_proto/__init__.py +0 -0
  171. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal_proto/api.proto +0 -0
  172. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal_proto/api_grpc.py +0 -0
  173. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal_proto/api_pb2.py +0 -0
  174. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal_proto/api_pb2.pyi +0 -0
  175. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal_proto/api_pb2_grpc.py +0 -0
  176. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal_proto/api_pb2_grpc.pyi +0 -0
  177. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal_proto/modal_api_grpc.py +0 -0
  178. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal_proto/modal_options_grpc.py +0 -0
  179. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal_proto/options.proto +0 -0
  180. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal_proto/options_grpc.py +0 -0
  181. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal_proto/options_pb2.py +0 -0
  182. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal_proto/options_pb2.pyi +0 -0
  183. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal_proto/options_pb2_grpc.py +0 -0
  184. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal_proto/options_pb2_grpc.pyi +0 -0
  185. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal_proto/py.typed +0 -0
  186. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/modal_version/__main__.py +0 -0
  187. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/pyproject.toml +0 -0
  188. {modal-1.1.1.dev25 → modal-1.1.1.dev27}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.1.1.dev25
3
+ Version: 1.1.1.dev27
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License: Apache-2.0
@@ -1,6 +1,7 @@
1
1
  # Copyright Modal Labs 2022
2
2
  import sys
3
3
 
4
+ from ._output import make_console
4
5
  from ._traceback import reduce_traceback_to_user_code
5
6
  from .cli._traceback import highlight_modal_warnings, setup_rich_traceback
6
7
  from .cli.entry_point import entrypoint_cli
@@ -35,7 +36,6 @@ def main():
35
36
  raise
36
37
 
37
38
  from grpclib import GRPCError, Status
38
- from rich.console import Console
39
39
  from rich.panel import Panel
40
40
  from rich.text import Text
41
41
 
@@ -68,7 +68,7 @@ def main():
68
68
  if notes := getattr(exc, "__notes__", []):
69
69
  content = f"{content}\n\nNote: {' '.join(notes)}"
70
70
 
71
- console = Console(stderr=True)
71
+ console = make_console(stderr=True)
72
72
  panel = Panel(Text(content), title=title, title_align="left", border_style="red")
73
73
  console.print(panel, highlight=False)
74
74
  sys.exit(1)
@@ -4,7 +4,6 @@ from __future__ import annotations
4
4
  import asyncio
5
5
  import contextlib
6
6
  import functools
7
- import io
8
7
  import platform
9
8
  import re
10
9
  import socket
@@ -46,6 +45,16 @@ else:
46
45
  default_spinner = "dots"
47
46
 
48
47
 
48
+ def make_console(*, stderr: bool = False, highlight: bool = True) -> Console:
49
+ """Create a rich Console tuned for Modal CLI output."""
50
+ return Console(
51
+ stderr=stderr,
52
+ highlight=highlight,
53
+ # CLI does not work with auto-detected Jupyter HTML display_data.
54
+ force_jupyter=False,
55
+ )
56
+
57
+
49
58
  class FunctionQueuingColumn(ProgressColumn):
50
59
  """Renders time elapsed, including task.completed as additional elapsed time."""
51
60
 
@@ -63,25 +72,6 @@ class FunctionQueuingColumn(ProgressColumn):
63
72
  return Text(str(delta), style="progress.elapsed")
64
73
 
65
74
 
66
- def download_progress_bar() -> Progress:
67
- """
68
- Returns a progress bar suitable for showing file download progress.
69
- Requires passing a `path: str` data field for rendering.
70
- """
71
- return Progress(
72
- TextColumn("[bold white]{task.fields[path]}", justify="right"),
73
- BarColumn(bar_width=None),
74
- "[progress.percentage]{task.percentage:>3.1f}%",
75
- "•",
76
- DownloadColumn(),
77
- "•",
78
- TransferSpeedColumn(),
79
- "•",
80
- TimeRemainingColumn(),
81
- transient=True,
82
- )
83
-
84
-
85
75
  class LineBufferedOutput:
86
76
  """Output stream that buffers lines and passes them to a callback."""
87
77
 
@@ -147,12 +137,11 @@ class OutputManager:
147
137
  def __init__(
148
138
  self,
149
139
  *,
150
- stdout: io.TextIOWrapper | None = None,
151
140
  status_spinner_text: str = "Running app...",
152
141
  show_timestamps: bool = False,
153
142
  ):
154
- self._stdout = stdout or sys.stdout
155
- self._console = Console(file=stdout, highlight=False)
143
+ self._stdout = sys.stdout
144
+ self._console = make_console(highlight=False)
156
145
  self._task_states = {}
157
146
  self._task_progress_items = {}
158
147
  self._current_render_group = None
@@ -6,12 +6,13 @@ import re
6
6
  import warnings
7
7
  from typing import Optional
8
8
 
9
- from rich.console import Console, RenderResult, group
9
+ from rich.console import RenderResult, group
10
10
  from rich.panel import Panel
11
11
  from rich.syntax import Syntax
12
12
  from rich.text import Text
13
13
  from rich.traceback import PathHighlighter, Stack, Traceback, install
14
14
 
15
+ from .._output import make_console
15
16
  from ..exception import DeprecationError, PendingDeprecationError, ServerWarning
16
17
 
17
18
 
@@ -193,7 +194,7 @@ def highlight_modal_warnings() -> None:
193
194
  title=title,
194
195
  title_align="left",
195
196
  )
196
- Console().print(panel)
197
+ make_console().print(panel)
197
198
  else:
198
199
  base_showwarning(warning, category, filename, lineno, file=None, line=None)
199
200
 
@@ -2,10 +2,10 @@
2
2
  from typing import Optional, Union
3
3
 
4
4
  import typer
5
- from rich.console import Console
6
5
  from rich.text import Text
7
6
 
8
7
  from modal._object import _get_environment_name
8
+ from modal._output import make_console
9
9
  from modal._pty import get_pty_info
10
10
  from modal._utils.async_utils import synchronizer
11
11
  from modal._utils.time_utils import timestamp_to_local
@@ -62,7 +62,7 @@ async def shell(
62
62
  if len(res.cluster.task_ids) <= rank:
63
63
  raise typer.Abort(f"No node with rank {rank} in cluster {cluster_id}")
64
64
  task_id = res.cluster.task_ids[rank]
65
- console = Console()
65
+ console = make_console()
66
66
  is_main = "(main)" if rank == 0 else ""
67
67
  console.print(
68
68
  f"Opening shell to node {rank} {is_main} of cluster {cluster_id} (container {task_id})", style="green"
@@ -1,7 +1,7 @@
1
1
  # Copyright Modal Labs 2022
2
2
  import typer
3
- from rich.console import Console
4
3
 
4
+ from modal._output import make_console
5
5
  from modal.config import _profile, _store_user_config, config
6
6
  from modal.environments import Environment
7
7
 
@@ -24,7 +24,7 @@ def show(redact: bool = typer.Option(True, help="Redact the `token_secret` value
24
24
  if redact and config_dict.get("token_secret"):
25
25
  config_dict["token_secret"] = "***"
26
26
 
27
- console = Console()
27
+ console = make_console()
28
28
  console.print(config_dict)
29
29
 
30
30
 
@@ -2,9 +2,9 @@
2
2
  from typing import Optional
3
3
 
4
4
  import typer
5
- from rich.console import Console
6
5
  from typer import Argument, Option, Typer
7
6
 
7
+ from modal._output import make_console
8
8
  from modal._resolver import Resolver
9
9
  from modal._utils.async_utils import synchronizer
10
10
  from modal._utils.grpc_utils import retry_transient_errors
@@ -85,7 +85,7 @@ async def get(name: str, key: str, *, env: Optional[str] = ENV_OPTION):
85
85
  Note: When using the CLI, keys are always interpreted as having a string type.
86
86
  """
87
87
  d = _Dict.from_name(name, environment_name=env)
88
- console = Console()
88
+ console = make_console()
89
89
  val = await d.get(key)
90
90
  console.print(val)
91
91
 
@@ -3,9 +3,9 @@ import subprocess
3
3
  from typing import Optional
4
4
 
5
5
  import typer
6
- from rich.console import Console
7
6
  from rich.rule import Rule
8
7
 
8
+ from modal._output import make_console
9
9
  from modal._utils.async_utils import synchronizer
10
10
 
11
11
  from . import run
@@ -71,7 +71,7 @@ def check_path():
71
71
  "You may need to give it permissions or use `[white]python -m modal[/white]` as a workaround.[/red]\n"
72
72
  )
73
73
  text += f"See more information here:\n\n[link={url}]{url}[/link]\n"
74
- console = Console()
74
+ console = make_console()
75
75
  console.print(text)
76
76
  console.print(Rule(style="white"))
77
77
 
@@ -19,9 +19,9 @@ from pathlib import Path
19
19
  from typing import Optional, Union, cast
20
20
 
21
21
  import click
22
- from rich.console import Console
23
22
  from rich.markdown import Markdown
24
23
 
24
+ from modal._output import make_console
25
25
  from modal._utils.deprecation import deprecation_warning
26
26
  from modal.app import App, LocalEntrypoint
27
27
  from modal.cls import Cls
@@ -258,7 +258,7 @@ def import_app_from_ref(import_ref: ImportRef, base_cmd: str = "") -> App:
258
258
  app = getattr(module, object_path)
259
259
 
260
260
  if app is None:
261
- error_console = Console(stderr=True)
261
+ error_console = make_console(stderr=True)
262
262
  error_console.print(f"[bold red]Could not find Modal app '{object_path}' in {import_path}.[/bold red]")
263
263
 
264
264
  if not object_path:
@@ -282,7 +282,7 @@ def import_app_from_ref(import_ref: ImportRef, base_cmd: str = "") -> App:
282
282
  def _show_function_ref_help(app_ref: ImportRef, base_cmd: str) -> None:
283
283
  object_path = app_ref.object_path
284
284
  import_path = app_ref.file_or_module
285
- error_console = Console(stderr=True)
285
+ error_console = make_console(stderr=True)
286
286
  if object_path:
287
287
  error_console.print(
288
288
  f"[bold red]Could not find Modal function or local entrypoint"
@@ -7,14 +7,13 @@ from typing import Optional
7
7
  import typer
8
8
  from click import UsageError
9
9
  from grpclib import GRPCError, Status
10
- from rich.console import Console
11
10
  from rich.syntax import Syntax
12
11
  from rich.table import Table
13
12
  from typer import Argument, Typer
14
13
 
15
14
  import modal
16
15
  from modal._location import display_location
17
- from modal._output import OutputManager, ProgressHandler
16
+ from modal._output import OutputManager, ProgressHandler, make_console
18
17
  from modal._utils.async_utils import synchronizer
19
18
  from modal._utils.grpc_utils import retry_transient_errors
20
19
  from modal._utils.time_utils import timestamp_to_local
@@ -66,7 +65,7 @@ def create(
66
65
  ):
67
66
  ensure_env(env)
68
67
  modal.NetworkFileSystem.create_deployed(name, environment_name=env)
69
- console = Console()
68
+ console = make_console()
70
69
  console.print(f"Created volume '{name}'. \n\nCode example:\n")
71
70
  usage = Syntax(gen_usage_code(name), "python")
72
71
  console.print(usage)
@@ -93,7 +92,7 @@ async def ls(
93
92
  raise
94
93
 
95
94
  if sys.stdout.isatty():
96
- console = Console()
95
+ console = make_console()
97
96
  console.print(f"Directory listing of '{path}' in '{volume_name}'")
98
97
  table = Table()
99
98
 
@@ -131,7 +130,7 @@ async def put(
131
130
  volume = _NetworkFileSystem.from_name(volume_name)
132
131
  if remote_path.endswith("/"):
133
132
  remote_path = remote_path + os.path.basename(local_path)
134
- console = Console()
133
+ console = make_console()
135
134
 
136
135
  if Path(local_path).is_dir():
137
136
  progress_handler = ProgressHandler(type="upload", console=console)
@@ -184,7 +183,7 @@ async def get(
184
183
  ensure_env(env)
185
184
  destination = Path(local_destination)
186
185
  volume = _NetworkFileSystem.from_name(volume_name)
187
- console = Console()
186
+ console = make_console()
188
187
  progress_handler = ProgressHandler(type="download", console=console)
189
188
  with progress_handler.live:
190
189
  await _volume_download(volume, remote_path, destination, force, progress_cb=progress_handler.progress)
@@ -203,7 +202,7 @@ async def rm(
203
202
  ):
204
203
  ensure_env(env)
205
204
  volume = _NetworkFileSystem.from_name(volume_name)
206
- console = Console()
205
+ console = make_console()
207
206
  try:
208
207
  await volume.remove_file(remote_path, recursive=recursive)
209
208
  console.print(OutputManager.step_completed(f"{remote_path} was deleted successfully!"))
@@ -5,10 +5,10 @@ import os
5
5
  from typing import Optional
6
6
 
7
7
  import typer
8
- from rich.console import Console
9
8
  from rich.json import JSON
10
9
  from rich.table import Table
11
10
 
11
+ from modal._output import make_console
12
12
  from modal._utils.async_utils import synchronizer
13
13
  from modal.config import Config, _lookup_workspace, _profile, config_profiles, config_set_active_profile
14
14
  from modal.exception import AuthError
@@ -69,7 +69,7 @@ async def list_(json: Optional[bool] = False):
69
69
  except AuthError:
70
70
  env_based_workspace = "Unknown (authentication failure)"
71
71
 
72
- console = Console()
72
+ console = make_console()
73
73
  highlight = "bold green" if env_based_workspace is None else "yellow"
74
74
  if json:
75
75
  json_data = []
@@ -2,9 +2,9 @@
2
2
  from typing import Optional
3
3
 
4
4
  import typer
5
- from rich.console import Console
6
5
  from typer import Argument, Option, Typer
7
6
 
7
+ from modal._output import make_console
8
8
  from modal._resolver import Resolver
9
9
  from modal._utils.async_utils import synchronizer
10
10
  from modal._utils.grpc_utils import retry_transient_errors
@@ -108,7 +108,7 @@ async def peek(
108
108
  ):
109
109
  """Print the next N items in the queue or queue partition (without removal)."""
110
110
  q = _Queue.from_name(name, environment_name=env)
111
- console = Console()
111
+ console = make_console()
112
112
  i = 0
113
113
  async for item in q.iterate(partition=partition):
114
114
  console.print(item)
@@ -128,5 +128,5 @@ async def len(
128
128
  ):
129
129
  """Print the length of a queue partition or the total length of all partitions."""
130
130
  q = _Queue.from_name(name, environment_name=env)
131
- console = Console()
131
+ console = make_console()
132
132
  console.print(await q.len(partition=partition, total=total))
@@ -9,10 +9,10 @@ from typing import Optional
9
9
 
10
10
  import click
11
11
  import typer
12
- from rich.console import Console
13
12
  from rich.syntax import Syntax
14
13
  from typer import Argument
15
14
 
15
+ from modal._output import make_console
16
16
  from modal._utils.async_utils import synchronizer
17
17
  from modal._utils.grpc_utils import retry_transient_errors
18
18
  from modal._utils.time_utils import timestamp_to_local
@@ -117,7 +117,7 @@ modal secret create my-credentials username=john password="$PASSWORD"
117
117
  await _Secret.create_deployed(secret_name, env_dict, overwrite=force)
118
118
 
119
119
  # Print code sample
120
- console = Console()
120
+ console = make_console()
121
121
  env_var_code = "\n ".join(f'os.getenv("{name}")' for name in env_dict.keys()) if env_dict else "..."
122
122
  example_code = f"""
123
123
  @app.function(secrets=[modal.Secret.from_name("{secret_name}")])
@@ -7,13 +7,12 @@ from typing import Optional, Union
7
7
  import typer
8
8
  from click import UsageError
9
9
  from grpclib import GRPCError, Status
10
- from rich.console import Console
11
10
  from rich.table import Column, Table
12
11
  from rich.text import Text
13
12
 
14
13
  from modal_proto import api_pb2
15
14
 
16
- from .._output import OutputManager, get_app_logs_loop
15
+ from .._output import OutputManager, get_app_logs_loop, make_console
17
16
  from .._utils.async_utils import synchronizer
18
17
  from ..client import _Client
19
18
  from ..environments import ensure_env
@@ -66,7 +65,7 @@ def _plain(text: Union[Text, str]) -> str:
66
65
 
67
66
 
68
67
  def is_tty() -> bool:
69
- return Console().is_terminal
68
+ return make_console().is_terminal
70
69
 
71
70
 
72
71
  def display_table(
@@ -78,7 +77,7 @@ def display_table(
78
77
  def col_to_str(col: Union[Column, str]) -> str:
79
78
  return str(col.header) if isinstance(col, Column) else col
80
79
 
81
- console = Console()
80
+ console = make_console()
82
81
  if json:
83
82
  json_data = [{col_to_str(col): _plain(row[i]) for i, col in enumerate(columns)} for row in rows]
84
83
  console.print_json(dumps(json_data))
@@ -7,12 +7,11 @@ from typing import Optional
7
7
  import typer
8
8
  from click import UsageError
9
9
  from grpclib import GRPCError, Status
10
- from rich.console import Console
11
10
  from rich.syntax import Syntax
12
11
  from typer import Argument, Option, Typer
13
12
 
14
13
  import modal
15
- from modal._output import OutputManager, ProgressHandler
14
+ from modal._output import OutputManager, ProgressHandler, make_console
16
15
  from modal._utils.async_utils import synchronizer
17
16
  from modal._utils.grpc_utils import retry_transient_errors
18
17
  from modal._utils.time_utils import timestamp_to_local
@@ -64,7 +63,7 @@ def some_func():
64
63
  os.listdir("/my_vol")
65
64
  """
66
65
 
67
- console = Console()
66
+ console = make_console()
68
67
  console.print(f"Created Volume '{name}' in environment '{env_name}'. \n\nCode example:\n")
69
68
  usage = Syntax(usage_code, "python")
70
69
  console.print(usage)
@@ -96,7 +95,7 @@ async def get(
96
95
  ensure_env(env)
97
96
  destination = Path(local_destination)
98
97
  volume = _Volume.from_name(volume_name, environment_name=env)
99
- console = Console()
98
+ console = make_console()
100
99
  progress_handler = ProgressHandler(type="download", console=console)
101
100
  with progress_handler.live:
102
101
  await _volume_download(volume, remote_path, destination, force, progress_cb=progress_handler.progress)
@@ -197,7 +196,7 @@ async def put(
197
196
 
198
197
  if remote_path.endswith("/"):
199
198
  remote_path = remote_path + os.path.basename(local_path)
200
- console = Console()
199
+ console = make_console()
201
200
  progress_handler = ProgressHandler(type="upload", console=console)
202
201
 
203
202
  if Path(local_path).is_dir():
@@ -245,7 +244,7 @@ async def rm(
245
244
  ):
246
245
  ensure_env(env)
247
246
  volume = _Volume.from_name(volume_name, environment_name=env)
248
- console = Console()
247
+ console = make_console()
249
248
  try:
250
249
  await volume.remove_file(remote_path, recursive=recursive)
251
250
  console.print(OutputManager.step_completed(f"{remote_path} was deleted successfully!"))
@@ -33,7 +33,7 @@ class _Client:
33
33
  server_url: str,
34
34
  client_type: int,
35
35
  credentials: typing.Optional[tuple[str, str]],
36
- version: str = "1.1.1.dev25",
36
+ version: str = "1.1.1.dev27",
37
37
  ):
38
38
  """mdmd:hidden
39
39
  The Modal client object is not intended to be instantiated directly by users.
@@ -164,7 +164,7 @@ class Client:
164
164
  server_url: str,
165
165
  client_type: int,
166
166
  credentials: typing.Optional[tuple[str, str]],
167
- version: str = "1.1.1.dev25",
167
+ version: str = "1.1.1.dev27",
168
168
  ):
169
169
  """mdmd:hidden
170
170
  The Modal client object is not intended to be instantiated directly by users.
@@ -144,9 +144,9 @@ class _ContainerProcess(Generic[T]):
144
144
  print("interactive exec is not currently supported on Windows.")
145
145
  return
146
146
 
147
- from rich.console import Console
147
+ from ._output import make_console
148
148
 
149
- console = Console()
149
+ console = make_console()
150
150
 
151
151
  connecting_status = console.status("Connecting...")
152
152
  connecting_status.start()
@@ -428,7 +428,7 @@ class Function(
428
428
 
429
429
  _call_generator: ___call_generator_spec[typing_extensions.Self]
430
430
 
431
- class __remote_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER, SUPERSELF]):
431
+ class __remote_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER, SUPERSELF]):
432
432
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> ReturnType_INNER:
433
433
  """Calls the function remotely, executing it with the given arguments and returning the execution's result."""
434
434
  ...
@@ -437,7 +437,7 @@ class Function(
437
437
  """Calls the function remotely, executing it with the given arguments and returning the execution's result."""
438
438
  ...
439
439
 
440
- remote: __remote_spec[modal._functions.ReturnType, modal._functions.P, typing_extensions.Self]
440
+ remote: __remote_spec[modal._functions.P, modal._functions.ReturnType, typing_extensions.Self]
441
441
 
442
442
  class __remote_gen_spec(typing_extensions.Protocol[SUPERSELF]):
443
443
  def __call__(self, /, *args, **kwargs) -> typing.Generator[typing.Any, None, None]:
@@ -464,7 +464,7 @@ class Function(
464
464
  """
465
465
  ...
466
466
 
467
- class ___experimental_spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER, SUPERSELF]):
467
+ class ___experimental_spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER, SUPERSELF]):
468
468
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
469
469
  """[Experimental] Calls the function with the given arguments, without waiting for the results.
470
470
 
@@ -488,7 +488,7 @@ class Function(
488
488
  ...
489
489
 
490
490
  _experimental_spawn: ___experimental_spawn_spec[
491
- modal._functions.ReturnType, modal._functions.P, typing_extensions.Self
491
+ modal._functions.P, modal._functions.ReturnType, typing_extensions.Self
492
492
  ]
493
493
 
494
494
  class ___spawn_map_inner_spec(typing_extensions.Protocol[P_INNER, SUPERSELF]):
@@ -497,7 +497,7 @@ class Function(
497
497
 
498
498
  _spawn_map_inner: ___spawn_map_inner_spec[modal._functions.P, typing_extensions.Self]
499
499
 
500
- class __spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER, SUPERSELF]):
500
+ class __spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER, SUPERSELF]):
501
501
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
502
502
  """Calls the function with the given arguments, without waiting for the results.
503
503
 
@@ -518,7 +518,7 @@ class Function(
518
518
  """
519
519
  ...
520
520
 
521
- spawn: __spawn_spec[modal._functions.ReturnType, modal._functions.P, typing_extensions.Self]
521
+ spawn: __spawn_spec[modal._functions.P, modal._functions.ReturnType, typing_extensions.Self]
522
522
 
523
523
  def get_raw_f(self) -> collections.abc.Callable[..., typing.Any]:
524
524
  """Return the inner Python object wrapped by this Modal Function."""
@@ -6,11 +6,11 @@ from collections.abc import AsyncGenerator
6
6
  from typing import Optional
7
7
 
8
8
  import aiohttp.web
9
- from rich.console import Console
10
9
  from synchronicity.async_wrap import asynccontextmanager
11
10
 
12
11
  from modal_proto import api_pb2
13
12
 
13
+ from ._output import make_console
14
14
  from ._utils.async_utils import synchronize_api
15
15
  from ._utils.http_utils import run_temporary_http_server
16
16
  from .client import _Client
@@ -76,7 +76,7 @@ async def _new_token(
76
76
  ):
77
77
  server_url = config.get("server_url", profile=profile)
78
78
 
79
- console = Console()
79
+ console = make_console()
80
80
 
81
81
  result: Optional[api_pb2.TokenFlowWaitResponse] = None
82
82
  async with _Client.anonymous(server_url) as client:
@@ -133,7 +133,7 @@ async def _set_token(
133
133
  ):
134
134
  # TODO add server_url as a parameter for verification?
135
135
  server_url = config.get("server_url", profile=profile)
136
- console = Console()
136
+ console = make_console()
137
137
  if verify:
138
138
  console.print(f"Verifying token against [blue]{server_url}[/blue]")
139
139
  await _Client.verify(server_url, (token_id, token_secret))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.1.1.dev25
3
+ Version: 1.1.1.dev27
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License: Apache-2.0
@@ -1,4 +1,4 @@
1
1
  # Copyright Modal Labs 2025
2
2
  """Supplies the current version of the modal client library."""
3
3
 
4
- __version__ = "1.1.1.dev25"
4
+ __version__ = "1.1.1.dev27"
File without changes
File without changes
File without changes