modal 1.1.2.dev17__tar.gz → 1.1.2.dev19__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 (190) hide show
  1. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/PKG-INFO +1 -1
  2. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/_functions.py +2 -1
  3. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/_object.py +13 -2
  4. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/client.pyi +2 -2
  5. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/cls.py +2 -1
  6. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/dict.py +19 -3
  7. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/experimental/__init__.py +28 -2
  8. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/functions.pyi +6 -6
  9. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/network_file_system.py +7 -1
  10. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/object.pyi +3 -0
  11. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/proxy.py +2 -1
  12. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/queue.py +12 -2
  13. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/secret.py +12 -2
  14. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/volume.py +19 -3
  15. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal.egg-info/PKG-INFO +1 -1
  16. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal_version/__init__.py +1 -1
  17. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/LICENSE +0 -0
  18. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/README.md +0 -0
  19. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/__init__.py +0 -0
  20. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/__main__.py +0 -0
  21. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/_clustered_functions.py +0 -0
  22. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/_clustered_functions.pyi +0 -0
  23. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/_container_entrypoint.py +0 -0
  24. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/_ipython.py +0 -0
  25. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/_location.py +0 -0
  26. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/_output.py +0 -0
  27. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/_partial_function.py +0 -0
  28. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/_pty.py +0 -0
  29. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/_resolver.py +0 -0
  30. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/_resources.py +0 -0
  31. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/_runtime/__init__.py +0 -0
  32. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/_runtime/asgi.py +0 -0
  33. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/_runtime/container_io_manager.py +0 -0
  34. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/_runtime/container_io_manager.pyi +0 -0
  35. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/_runtime/execution_context.py +0 -0
  36. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/_runtime/execution_context.pyi +0 -0
  37. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/_runtime/gpu_memory_snapshot.py +0 -0
  38. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/_runtime/telemetry.py +0 -0
  39. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/_runtime/user_code_imports.py +0 -0
  40. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/_serialization.py +0 -0
  41. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/_traceback.py +0 -0
  42. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/_tunnel.py +0 -0
  43. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/_tunnel.pyi +0 -0
  44. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/_type_manager.py +0 -0
  45. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/_utils/__init__.py +0 -0
  46. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/_utils/app_utils.py +0 -0
  47. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/_utils/async_utils.py +0 -0
  48. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/_utils/auth_token_manager.py +0 -0
  49. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/_utils/blob_utils.py +0 -0
  50. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/_utils/bytes_io_segment_payload.py +0 -0
  51. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/_utils/deprecation.py +0 -0
  52. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/_utils/docker_utils.py +0 -0
  53. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/_utils/function_utils.py +0 -0
  54. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/_utils/git_utils.py +0 -0
  55. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/_utils/grpc_testing.py +0 -0
  56. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/_utils/grpc_utils.py +0 -0
  57. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/_utils/hash_utils.py +0 -0
  58. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/_utils/http_utils.py +0 -0
  59. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/_utils/jwt_utils.py +0 -0
  60. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/_utils/logger.py +0 -0
  61. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/_utils/mount_utils.py +0 -0
  62. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/_utils/name_utils.py +0 -0
  63. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/_utils/package_utils.py +0 -0
  64. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/_utils/pattern_utils.py +0 -0
  65. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/_utils/rand_pb_testing.py +0 -0
  66. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/_utils/shell_utils.py +0 -0
  67. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/_utils/time_utils.py +0 -0
  68. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/_vendor/__init__.py +0 -0
  69. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/_vendor/a2wsgi_wsgi.py +0 -0
  70. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/_vendor/cloudpickle.py +0 -0
  71. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/_vendor/tblib.py +0 -0
  72. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/_watcher.py +0 -0
  73. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/app.py +0 -0
  74. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/app.pyi +0 -0
  75. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/builder/2023.12.312.txt +0 -0
  76. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/builder/2023.12.txt +0 -0
  77. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/builder/2024.04.txt +0 -0
  78. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/builder/2024.10.txt +0 -0
  79. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/builder/2025.06.txt +0 -0
  80. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/builder/PREVIEW.txt +0 -0
  81. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/builder/README.md +0 -0
  82. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/builder/base-images.json +0 -0
  83. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/call_graph.py +0 -0
  84. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/cli/__init__.py +0 -0
  85. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/cli/_download.py +0 -0
  86. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/cli/_traceback.py +0 -0
  87. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/cli/app.py +0 -0
  88. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/cli/cluster.py +0 -0
  89. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/cli/config.py +0 -0
  90. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/cli/container.py +0 -0
  91. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/cli/dict.py +0 -0
  92. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/cli/entry_point.py +0 -0
  93. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/cli/environment.py +0 -0
  94. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/cli/import_refs.py +0 -0
  95. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/cli/launch.py +0 -0
  96. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/cli/network_file_system.py +0 -0
  97. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/cli/profile.py +0 -0
  98. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/cli/programs/__init__.py +0 -0
  99. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/cli/programs/launch_instance_ssh.py +0 -0
  100. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/cli/programs/run_jupyter.py +0 -0
  101. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/cli/programs/run_marimo.py +0 -0
  102. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/cli/programs/vscode.py +0 -0
  103. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/cli/queues.py +0 -0
  104. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/cli/run.py +0 -0
  105. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/cli/secret.py +0 -0
  106. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/cli/token.py +0 -0
  107. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/cli/utils.py +0 -0
  108. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/cli/volume.py +0 -0
  109. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/client.py +0 -0
  110. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/cloud_bucket_mount.py +0 -0
  111. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/cloud_bucket_mount.pyi +0 -0
  112. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/cls.pyi +0 -0
  113. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/config.py +0 -0
  114. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/container_process.py +0 -0
  115. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/container_process.pyi +0 -0
  116. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/dict.pyi +0 -0
  117. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/environments.py +0 -0
  118. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/environments.pyi +0 -0
  119. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/exception.py +0 -0
  120. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/experimental/flash.py +0 -0
  121. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/experimental/flash.pyi +0 -0
  122. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/experimental/ipython.py +0 -0
  123. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/file_io.py +0 -0
  124. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/file_io.pyi +0 -0
  125. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/file_pattern_matcher.py +0 -0
  126. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/functions.py +0 -0
  127. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/gpu.py +0 -0
  128. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/image.py +0 -0
  129. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/image.pyi +0 -0
  130. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/io_streams.py +0 -0
  131. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/io_streams.pyi +0 -0
  132. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/mount.py +0 -0
  133. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/mount.pyi +0 -0
  134. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/network_file_system.pyi +0 -0
  135. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/object.py +0 -0
  136. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/output.py +0 -0
  137. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/parallel_map.py +0 -0
  138. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/parallel_map.pyi +0 -0
  139. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/partial_function.py +0 -0
  140. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/partial_function.pyi +0 -0
  141. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/proxy.pyi +0 -0
  142. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/py.typed +0 -0
  143. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/queue.pyi +0 -0
  144. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/retries.py +0 -0
  145. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/runner.py +0 -0
  146. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/runner.pyi +0 -0
  147. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/running_app.py +0 -0
  148. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/sandbox.py +0 -0
  149. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/sandbox.pyi +0 -0
  150. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/schedule.py +0 -0
  151. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/scheduler_placement.py +0 -0
  152. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/secret.pyi +0 -0
  153. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/serving.py +0 -0
  154. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/serving.pyi +0 -0
  155. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/snapshot.py +0 -0
  156. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/snapshot.pyi +0 -0
  157. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/stream_type.py +0 -0
  158. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/token_flow.py +0 -0
  159. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/token_flow.pyi +0 -0
  160. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal/volume.pyi +0 -0
  161. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal.egg-info/SOURCES.txt +0 -0
  162. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal.egg-info/dependency_links.txt +0 -0
  163. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal.egg-info/entry_points.txt +0 -0
  164. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal.egg-info/requires.txt +0 -0
  165. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal.egg-info/top_level.txt +0 -0
  166. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal_docs/__init__.py +0 -0
  167. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal_docs/gen_cli_docs.py +0 -0
  168. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal_docs/gen_reference_docs.py +0 -0
  169. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal_docs/mdmd/__init__.py +0 -0
  170. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal_docs/mdmd/mdmd.py +0 -0
  171. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal_docs/mdmd/signatures.py +0 -0
  172. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal_proto/__init__.py +0 -0
  173. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal_proto/api.proto +0 -0
  174. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal_proto/api_grpc.py +0 -0
  175. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal_proto/api_pb2.py +0 -0
  176. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal_proto/api_pb2.pyi +0 -0
  177. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal_proto/api_pb2_grpc.py +0 -0
  178. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal_proto/api_pb2_grpc.pyi +0 -0
  179. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal_proto/modal_api_grpc.py +0 -0
  180. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal_proto/modal_options_grpc.py +0 -0
  181. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal_proto/options.proto +0 -0
  182. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal_proto/options_grpc.py +0 -0
  183. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal_proto/options_pb2.py +0 -0
  184. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal_proto/options_pb2.pyi +0 -0
  185. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal_proto/options_pb2_grpc.py +0 -0
  186. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal_proto/options_pb2_grpc.pyi +0 -0
  187. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal_proto/py.typed +0 -0
  188. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/modal_version/__main__.py +0 -0
  189. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/pyproject.toml +0 -0
  190. {modal-1.1.2.dev17 → modal-1.1.2.dev19}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.1.2.dev17
3
+ Version: 1.1.2.dev19
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License: Apache-2.0
@@ -1276,7 +1276,8 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
1276
1276
 
1277
1277
  self._hydrate(response.function_id, resolver.client, response.handle_metadata)
1278
1278
 
1279
- rep = f"Function.from_name('{app_name}', '{name}')"
1279
+ environment_rep = f", environment_name={environment_name!r}" if environment_name else ""
1280
+ rep = f"modal.Function.from_name('{app_name}', '{name}'{environment_rep})"
1280
1281
  return cls._from_loader(_load_remote, rep, is_another_app=True, hydrate_lazily=True)
1281
1282
 
1282
1283
  @classmethod
@@ -191,9 +191,20 @@ class _Object:
191
191
  def _is_id_type(cls, object_id) -> bool:
192
192
  return cls._get_type_from_id(object_id) == cls
193
193
 
194
+ @classmethod
195
+ def _repr(cls, name: str, environment_name: Optional[str] = None) -> str:
196
+ public_cls = cls.__name__.strip("_")
197
+ environment_repr = f", environment_name={environment_name!r}" if environment_name else ""
198
+ return f"modal.{public_cls}.from_name({name!r}{environment_repr})"
199
+
194
200
  @classmethod
195
201
  def _new_hydrated(
196
- cls, object_id: str, client: _Client, handle_metadata: Optional[Message], is_another_app: bool = False
202
+ cls,
203
+ object_id: str,
204
+ client: _Client,
205
+ handle_metadata: Optional[Message],
206
+ is_another_app: bool = False,
207
+ rep: Optional[str] = None,
197
208
  ) -> Self:
198
209
  obj_cls: type[Self]
199
210
  if cls._type_prefix is not None:
@@ -210,7 +221,7 @@ class _Object:
210
221
 
211
222
  # Instantiate provider
212
223
  obj = _Object.__new__(obj_cls)
213
- rep = f"Object({object_id})" # TODO(erikbern): dumb
224
+ rep = rep or f"modal.{obj_cls.__name__.strip('_')}.from_id({object_id!r})"
214
225
  obj._init(rep, is_another_app=is_another_app)
215
226
  obj._hydrate(object_id, client, handle_metadata)
216
227
 
@@ -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.2.dev17",
36
+ version: str = "1.1.2.dev19",
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.2.dev17",
167
+ version: str = "1.1.2.dev19",
168
168
  ):
169
169
  """mdmd:hidden
170
170
  The Modal client object is not intended to be instantiated directly by users.
@@ -657,7 +657,8 @@ More information on class parameterization can be found here: https://modal.com/
657
657
  await resolver.load(self._class_service_function)
658
658
  self._hydrate(response.class_id, resolver.client, response.handle_metadata)
659
659
 
660
- rep = f"Cls.from_name({app_name!r}, {name!r})"
660
+ environment_rep = f", environment_name={environment_name!r}" if environment_name else ""
661
+ rep = f"Cls.from_name({app_name!r}, {name!r}{environment_rep})"
661
662
  cls = cls._from_loader(_load_remote, rep, is_another_app=True, hydrate_lazily=True)
662
663
 
663
664
  class_service_name = f"{name}.*" # special name of the base service function for the class
@@ -101,7 +101,16 @@ class _DictManager:
101
101
  break
102
102
  finished = await retrieve_page(items[-1].metadata.creation_info.created_at)
103
103
 
104
- dicts = [_Dict._new_hydrated(item.dict_id, client, item.metadata, is_another_app=True) for item in items]
104
+ dicts = [
105
+ _Dict._new_hydrated(
106
+ item.dict_id,
107
+ client,
108
+ item.metadata,
109
+ is_another_app=True,
110
+ rep=_Dict._repr(item.name, environment_name),
111
+ )
112
+ for item in items
113
+ ]
105
114
  return dicts[:max_objects] if max_objects is not None else dicts
106
115
 
107
116
  @staticmethod
@@ -252,7 +261,13 @@ class _Dict(_Object, type_prefix="di"):
252
261
  async with TaskContext() as tc:
253
262
  request = api_pb2.DictHeartbeatRequest(dict_id=response.dict_id)
254
263
  tc.infinite_loop(lambda: client.stub.DictHeartbeat(request), sleep=_heartbeat_sleep)
255
- yield cls._new_hydrated(response.dict_id, client, response.metadata, is_another_app=True)
264
+ yield cls._new_hydrated(
265
+ response.dict_id,
266
+ client,
267
+ response.metadata,
268
+ is_another_app=True,
269
+ rep="modal.Dict.ephemeral()",
270
+ )
256
271
 
257
272
  @staticmethod
258
273
  def from_name(
@@ -295,7 +310,8 @@ class _Dict(_Object, type_prefix="di"):
295
310
  logger.debug(f"Created dict with id {response.dict_id}")
296
311
  self._hydrate(response.dict_id, resolver.client, response.metadata)
297
312
 
298
- return _Dict._from_loader(_load, "Dict()", is_another_app=True, hydrate_lazily=True, name=name)
313
+ rep = _Dict._repr(name, environment_name)
314
+ return _Dict._from_loader(_load, rep, is_another_app=True, hydrate_lazily=True, name=name)
299
315
 
300
316
  @staticmethod
301
317
  async def lookup(
@@ -213,6 +213,24 @@ async def raw_registry_image(
213
213
  )
214
214
 
215
215
 
216
+ def _install_cuda_command() -> str:
217
+ """Command to install CUDA Toolkit (nvcc) inside a container."""
218
+ arch = "x86_64" # instruction set architecture for the CPU, all Modal machines are x86_64
219
+ distro = "debian12" # the distribution and version number of our OS (GNU/Linux)
220
+ filename = "cuda-keyring_1.1-1_all.deb" # NVIDIA signing key file
221
+ cuda_keyring_url = f"https://developer.download.nvidia.com/compute/cuda/repos/{distro}/{arch}/{filename}"
222
+
223
+ major, minor = 12, 8
224
+ max_cuda_version = f"{major}-{minor}"
225
+
226
+ return (
227
+ f"wget {cuda_keyring_url} && "
228
+ + f"dpkg -i {filename} && "
229
+ + f"rm -f {filename} && "
230
+ + f"apt-get update && apt-get install -y cuda-nvcc-{max_cuda_version}"
231
+ )
232
+
233
+
216
234
  @synchronizer.create_blocking
217
235
  async def notebook_base_image(*, python_version: Optional[str] = None, force_build: bool = False) -> _Image:
218
236
  """Default image used for Modal notebook kernels, with common libraries.
@@ -293,7 +311,8 @@ async def notebook_base_image(*, python_version: Optional[str] = None, force_bui
293
311
 
294
312
  commands: list[str] = [
295
313
  "apt-get update",
296
- "apt-get install -y libpq-dev pkg-config cmake git curl wget unzip zip libsqlite3-dev openssh-server",
314
+ "apt-get install -y libpq-dev pkg-config cmake git curl wget unzip zip libsqlite3-dev openssh-server vim",
315
+ _install_cuda_command(),
297
316
  # Install uv since it's faster than pip for installing packages.
298
317
  "pip install uv",
299
318
  # https://github.com/astral-sh/uv/issues/11480
@@ -306,7 +325,14 @@ async def notebook_base_image(*, python_version: Optional[str] = None, force_bui
306
325
  # https://github.com/charlesfrye/cuda-modal/blob/7fef8db12402986cf42d9c8cca8c63d1da6d7700/cuda/use_cuda.py#L158-L188
307
326
 
308
327
  def build_dockerfile(version: ImageBuilderVersion) -> DockerfileSpec:
309
- return DockerfileSpec(commands=["FROM base", *(f"RUN {cmd}" for cmd in commands)], context_files={})
328
+ return DockerfileSpec(
329
+ commands=[
330
+ "FROM base",
331
+ *(f"RUN {cmd}" for cmd in commands),
332
+ "ENV PATH=/usr/local/cuda/bin:$PATH",
333
+ ],
334
+ context_files={},
335
+ )
310
336
 
311
337
  return _Image._from_args(
312
338
  base_images={"base": base_image},
@@ -433,7 +433,7 @@ class Function(
433
433
 
434
434
  _call_generator: ___call_generator_spec[typing_extensions.Self]
435
435
 
436
- class __remote_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER, SUPERSELF]):
436
+ class __remote_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER, SUPERSELF]):
437
437
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> ReturnType_INNER:
438
438
  """Calls the function remotely, executing it with the given arguments and returning the execution's result."""
439
439
  ...
@@ -442,7 +442,7 @@ class Function(
442
442
  """Calls the function remotely, executing it with the given arguments and returning the execution's result."""
443
443
  ...
444
444
 
445
- remote: __remote_spec[modal._functions.P, modal._functions.ReturnType, typing_extensions.Self]
445
+ remote: __remote_spec[modal._functions.ReturnType, modal._functions.P, typing_extensions.Self]
446
446
 
447
447
  class __remote_gen_spec(typing_extensions.Protocol[SUPERSELF]):
448
448
  def __call__(self, /, *args, **kwargs) -> typing.Generator[typing.Any, None, None]:
@@ -469,7 +469,7 @@ class Function(
469
469
  """
470
470
  ...
471
471
 
472
- class ___experimental_spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER, SUPERSELF]):
472
+ class ___experimental_spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER, SUPERSELF]):
473
473
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
474
474
  """[Experimental] Calls the function with the given arguments, without waiting for the results.
475
475
 
@@ -493,7 +493,7 @@ class Function(
493
493
  ...
494
494
 
495
495
  _experimental_spawn: ___experimental_spawn_spec[
496
- modal._functions.P, modal._functions.ReturnType, typing_extensions.Self
496
+ modal._functions.ReturnType, modal._functions.P, typing_extensions.Self
497
497
  ]
498
498
 
499
499
  class ___spawn_map_inner_spec(typing_extensions.Protocol[P_INNER, SUPERSELF]):
@@ -502,7 +502,7 @@ class Function(
502
502
 
503
503
  _spawn_map_inner: ___spawn_map_inner_spec[modal._functions.P, typing_extensions.Self]
504
504
 
505
- class __spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER, SUPERSELF]):
505
+ class __spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER, SUPERSELF]):
506
506
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
507
507
  """Calls the function with the given arguments, without waiting for the results.
508
508
 
@@ -523,7 +523,7 @@ class Function(
523
523
  """
524
524
  ...
525
525
 
526
- spawn: __spawn_spec[modal._functions.P, modal._functions.ReturnType, typing_extensions.Self]
526
+ spawn: __spawn_spec[modal._functions.ReturnType, modal._functions.P, typing_extensions.Self]
527
527
 
528
528
  def get_raw_f(self) -> collections.abc.Callable[..., typing.Any]:
529
529
  """Return the inner Python object wrapped by this Modal Function."""
@@ -161,7 +161,13 @@ class _NetworkFileSystem(_Object, type_prefix="sv"):
161
161
  async with TaskContext() as tc:
162
162
  request = api_pb2.SharedVolumeHeartbeatRequest(shared_volume_id=response.shared_volume_id)
163
163
  tc.infinite_loop(lambda: client.stub.SharedVolumeHeartbeat(request), sleep=_heartbeat_sleep)
164
- yield cls._new_hydrated(response.shared_volume_id, client, None, is_another_app=True)
164
+ yield cls._new_hydrated(
165
+ response.shared_volume_id,
166
+ client,
167
+ None,
168
+ is_another_app=True,
169
+ rep="modal.NetworkFileSystem.ephemeral()",
170
+ )
165
171
 
166
172
  @staticmethod
167
173
  async def lookup(
@@ -117,12 +117,15 @@ class Object:
117
117
  @classmethod
118
118
  def _is_id_type(cls, object_id) -> bool: ...
119
119
  @classmethod
120
+ def _repr(cls, name: str, environment_name: typing.Optional[str] = None) -> str: ...
121
+ @classmethod
120
122
  def _new_hydrated(
121
123
  cls,
122
124
  object_id: str,
123
125
  client: modal.client.Client,
124
126
  handle_metadata: typing.Optional[google.protobuf.message.Message],
125
127
  is_another_app: bool = False,
128
+ rep: typing.Optional[str] = None,
126
129
  ) -> typing_extensions.Self: ...
127
130
  def _hydrate_from_other(self, other: typing_extensions.Self): ...
128
131
  def __repr__(self): ...
@@ -36,7 +36,8 @@ class _Proxy(_Object, type_prefix="pr"):
36
36
  response: api_pb2.ProxyGetResponse = await resolver.client.stub.ProxyGet(req)
37
37
  self._hydrate(response.proxy.proxy_id, resolver.client, None)
38
38
 
39
- return _Proxy._from_loader(_load, "Proxy()", is_another_app=True)
39
+ rep = _Proxy._repr(name, environment_name)
40
+ return _Proxy._from_loader(_load, rep, is_another_app=True)
40
41
 
41
42
 
42
43
  Proxy = synchronize_api(_Proxy, target_module=__name__)
@@ -99,7 +99,16 @@ class _QueueManager:
99
99
  break
100
100
  finished = await retrieve_page(items[-1].metadata.creation_info.created_at)
101
101
 
102
- queues = [_Queue._new_hydrated(item.queue_id, client, item.metadata, is_another_app=True) for item in items]
102
+ queues = [
103
+ _Queue._new_hydrated(
104
+ item.queue_id,
105
+ client,
106
+ item.metadata,
107
+ is_another_app=True,
108
+ rep=_Queue._repr(item.name, environment_name),
109
+ )
110
+ for item in items
111
+ ]
103
112
  return queues[:max_objects] if max_objects is not None else queues
104
113
 
105
114
  @staticmethod
@@ -314,7 +323,8 @@ class _Queue(_Object, type_prefix="qu"):
314
323
  response = await resolver.client.stub.QueueGetOrCreate(req)
315
324
  self._hydrate(response.queue_id, resolver.client, response.metadata)
316
325
 
317
- return _Queue._from_loader(_load, "Queue()", is_another_app=True, hydrate_lazily=True, name=name)
326
+ rep = _Queue._repr(name, environment_name)
327
+ return _Queue._from_loader(_load, rep, is_another_app=True, hydrate_lazily=True, name=name)
318
328
 
319
329
  @staticmethod
320
330
  async def lookup(
@@ -91,7 +91,16 @@ class _SecretManager:
91
91
  break
92
92
  finished = await retrieve_page(items[-1].metadata.creation_info.created_at)
93
93
 
94
- secrets = [_Secret._new_hydrated(item.secret_id, client, item.metadata, is_another_app=True) for item in items]
94
+ secrets = [
95
+ _Secret._new_hydrated(
96
+ item.secret_id,
97
+ client,
98
+ item.metadata,
99
+ is_another_app=True,
100
+ rep=_Secret._repr(item.label, environment_name),
101
+ )
102
+ for item in items
103
+ ]
95
104
  return secrets[:max_objects] if max_objects is not None else secrets
96
105
 
97
106
  @staticmethod
@@ -334,7 +343,8 @@ class _Secret(_Object, type_prefix="st"):
334
343
  raise
335
344
  self._hydrate(response.secret_id, resolver.client, response.metadata)
336
345
 
337
- return _Secret._from_loader(_load, "Secret()", hydrate_lazily=True, name=name)
346
+ rep = _Secret._repr(name, environment_name)
347
+ return _Secret._from_loader(_load, rep, hydrate_lazily=True, name=name)
338
348
 
339
349
  @staticmethod
340
350
  async def lookup(
@@ -168,7 +168,16 @@ class _VolumeManager:
168
168
  break
169
169
  finished = await retrieve_page(items[-1].metadata.creation_info.created_at)
170
170
 
171
- volumes = [_Volume._new_hydrated(item.volume_id, client, item.metadata, is_another_app=True) for item in items]
171
+ volumes = [
172
+ _Volume._new_hydrated(
173
+ item.volume_id,
174
+ client,
175
+ item.metadata,
176
+ is_another_app=True,
177
+ rep=_Volume._repr(item.label, environment_name),
178
+ )
179
+ for item in items
180
+ ]
172
181
  return volumes[:max_objects] if max_objects is not None else volumes
173
182
 
174
183
  @staticmethod
@@ -362,7 +371,8 @@ class _Volume(_Object, type_prefix="vo"):
362
371
  response = await resolver.client.stub.VolumeGetOrCreate(req)
363
372
  self._hydrate(response.volume_id, resolver.client, response.metadata)
364
373
 
365
- return _Volume._from_loader(_load, "Volume()", hydrate_lazily=True, name=name)
374
+ rep = _Volume._repr(name, environment_name)
375
+ return _Volume._from_loader(_load, rep, hydrate_lazily=True, name=name)
366
376
 
367
377
  @classmethod
368
378
  @asynccontextmanager
@@ -398,7 +408,13 @@ class _Volume(_Object, type_prefix="vo"):
398
408
  async with TaskContext() as tc:
399
409
  request = api_pb2.VolumeHeartbeatRequest(volume_id=response.volume_id)
400
410
  tc.infinite_loop(lambda: client.stub.VolumeHeartbeat(request), sleep=_heartbeat_sleep)
401
- yield cls._new_hydrated(response.volume_id, client, response.metadata, is_another_app=True)
411
+ yield cls._new_hydrated(
412
+ response.volume_id,
413
+ client,
414
+ response.metadata,
415
+ is_another_app=True,
416
+ rep="modal.Volume.ephemeral()",
417
+ )
402
418
 
403
419
  @staticmethod
404
420
  async def lookup(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.1.2.dev17
3
+ Version: 1.1.2.dev19
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.2.dev17"
4
+ __version__ = "1.1.2.dev19"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes