modal 1.1.5.dev20__tar.gz → 1.1.5.dev22__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 (190) hide show
  1. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/PKG-INFO +1 -1
  2. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/_functions.py +12 -4
  3. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/app.py +12 -3
  4. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/app.pyi +8 -4
  5. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/client.pyi +2 -2
  6. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/cls.py +7 -2
  7. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/cls.pyi +7 -5
  8. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/functions.pyi +6 -2
  9. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/image.py +85 -15
  10. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/image.pyi +54 -28
  11. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/sandbox.py +31 -14
  12. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/sandbox.pyi +32 -17
  13. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/secret.py +1 -1
  14. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal.egg-info/PKG-INFO +1 -1
  15. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal_version/__init__.py +1 -1
  16. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/LICENSE +0 -0
  17. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/README.md +0 -0
  18. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/__init__.py +0 -0
  19. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/__main__.py +0 -0
  20. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/_clustered_functions.py +0 -0
  21. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/_clustered_functions.pyi +0 -0
  22. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/_container_entrypoint.py +0 -0
  23. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/_ipython.py +0 -0
  24. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/_location.py +0 -0
  25. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/_object.py +0 -0
  26. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/_output.py +0 -0
  27. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/_partial_function.py +0 -0
  28. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/_pty.py +0 -0
  29. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/_resolver.py +0 -0
  30. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/_resources.py +0 -0
  31. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/_runtime/__init__.py +0 -0
  32. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/_runtime/asgi.py +0 -0
  33. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/_runtime/container_io_manager.py +0 -0
  34. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/_runtime/container_io_manager.pyi +0 -0
  35. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/_runtime/execution_context.py +0 -0
  36. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/_runtime/execution_context.pyi +0 -0
  37. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/_runtime/gpu_memory_snapshot.py +0 -0
  38. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/_runtime/telemetry.py +0 -0
  39. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/_runtime/user_code_imports.py +0 -0
  40. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/_serialization.py +0 -0
  41. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/_traceback.py +0 -0
  42. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/_tunnel.py +0 -0
  43. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/_tunnel.pyi +0 -0
  44. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/_type_manager.py +0 -0
  45. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/_utils/__init__.py +0 -0
  46. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/_utils/app_utils.py +0 -0
  47. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/_utils/async_utils.py +0 -0
  48. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/_utils/auth_token_manager.py +0 -0
  49. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/_utils/blob_utils.py +0 -0
  50. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/_utils/bytes_io_segment_payload.py +0 -0
  51. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/_utils/deprecation.py +0 -0
  52. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/_utils/docker_utils.py +0 -0
  53. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/_utils/function_utils.py +0 -0
  54. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/_utils/git_utils.py +0 -0
  55. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/_utils/grpc_testing.py +0 -0
  56. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/_utils/grpc_utils.py +0 -0
  57. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/_utils/hash_utils.py +0 -0
  58. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/_utils/http_utils.py +0 -0
  59. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/_utils/jwt_utils.py +0 -0
  60. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/_utils/logger.py +0 -0
  61. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/_utils/mount_utils.py +0 -0
  62. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/_utils/name_utils.py +0 -0
  63. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/_utils/package_utils.py +0 -0
  64. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/_utils/pattern_utils.py +0 -0
  65. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/_utils/rand_pb_testing.py +0 -0
  66. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/_utils/shell_utils.py +0 -0
  67. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/_utils/time_utils.py +0 -0
  68. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/_vendor/__init__.py +0 -0
  69. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/_vendor/a2wsgi_wsgi.py +0 -0
  70. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/_vendor/cloudpickle.py +0 -0
  71. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/_vendor/tblib.py +0 -0
  72. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/_watcher.py +0 -0
  73. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/builder/2023.12.312.txt +0 -0
  74. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/builder/2023.12.txt +0 -0
  75. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/builder/2024.04.txt +0 -0
  76. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/builder/2024.10.txt +0 -0
  77. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/builder/2025.06.txt +0 -0
  78. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/builder/PREVIEW.txt +0 -0
  79. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/builder/README.md +0 -0
  80. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/builder/base-images.json +0 -0
  81. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/call_graph.py +0 -0
  82. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/cli/__init__.py +0 -0
  83. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/cli/_download.py +0 -0
  84. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/cli/_traceback.py +0 -0
  85. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/cli/app.py +0 -0
  86. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/cli/cluster.py +0 -0
  87. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/cli/config.py +0 -0
  88. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/cli/container.py +0 -0
  89. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/cli/dict.py +0 -0
  90. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/cli/entry_point.py +0 -0
  91. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/cli/environment.py +0 -0
  92. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/cli/import_refs.py +0 -0
  93. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/cli/launch.py +0 -0
  94. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/cli/network_file_system.py +0 -0
  95. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/cli/profile.py +0 -0
  96. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/cli/programs/__init__.py +0 -0
  97. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/cli/programs/launch_instance_ssh.py +0 -0
  98. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/cli/programs/run_jupyter.py +0 -0
  99. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/cli/programs/run_marimo.py +0 -0
  100. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/cli/programs/vscode.py +0 -0
  101. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/cli/queues.py +0 -0
  102. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/cli/run.py +0 -0
  103. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/cli/secret.py +0 -0
  104. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/cli/token.py +0 -0
  105. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/cli/utils.py +0 -0
  106. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/cli/volume.py +0 -0
  107. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/client.py +0 -0
  108. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/cloud_bucket_mount.py +0 -0
  109. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/cloud_bucket_mount.pyi +0 -0
  110. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/config.py +0 -0
  111. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/container_process.py +0 -0
  112. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/container_process.pyi +0 -0
  113. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/dict.py +0 -0
  114. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/dict.pyi +0 -0
  115. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/environments.py +0 -0
  116. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/environments.pyi +0 -0
  117. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/exception.py +0 -0
  118. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/experimental/__init__.py +0 -0
  119. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/experimental/flash.py +0 -0
  120. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/experimental/flash.pyi +0 -0
  121. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/experimental/ipython.py +0 -0
  122. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/file_io.py +0 -0
  123. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/file_io.pyi +0 -0
  124. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/file_pattern_matcher.py +0 -0
  125. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/functions.py +0 -0
  126. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/gpu.py +0 -0
  127. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/io_streams.py +0 -0
  128. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/io_streams.pyi +0 -0
  129. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/mount.py +0 -0
  130. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/mount.pyi +0 -0
  131. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/network_file_system.py +0 -0
  132. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/network_file_system.pyi +0 -0
  133. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/object.py +0 -0
  134. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/object.pyi +0 -0
  135. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/output.py +0 -0
  136. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/parallel_map.py +0 -0
  137. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/parallel_map.pyi +0 -0
  138. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/partial_function.py +0 -0
  139. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/partial_function.pyi +0 -0
  140. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/proxy.py +0 -0
  141. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/proxy.pyi +0 -0
  142. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/py.typed +0 -0
  143. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/queue.py +0 -0
  144. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/queue.pyi +0 -0
  145. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/retries.py +0 -0
  146. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/runner.py +0 -0
  147. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/runner.pyi +0 -0
  148. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/running_app.py +0 -0
  149. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/schedule.py +0 -0
  150. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/scheduler_placement.py +0 -0
  151. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/secret.pyi +0 -0
  152. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/serving.py +0 -0
  153. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/serving.pyi +0 -0
  154. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/snapshot.py +0 -0
  155. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/snapshot.pyi +0 -0
  156. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/stream_type.py +0 -0
  157. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/token_flow.py +0 -0
  158. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/token_flow.pyi +0 -0
  159. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/volume.py +0 -0
  160. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal/volume.pyi +0 -0
  161. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal.egg-info/SOURCES.txt +0 -0
  162. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal.egg-info/dependency_links.txt +0 -0
  163. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal.egg-info/entry_points.txt +0 -0
  164. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal.egg-info/requires.txt +0 -0
  165. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal.egg-info/top_level.txt +0 -0
  166. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal_docs/__init__.py +0 -0
  167. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal_docs/gen_cli_docs.py +0 -0
  168. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal_docs/gen_reference_docs.py +0 -0
  169. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal_docs/mdmd/__init__.py +0 -0
  170. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal_docs/mdmd/mdmd.py +0 -0
  171. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal_docs/mdmd/signatures.py +0 -0
  172. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal_proto/__init__.py +0 -0
  173. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal_proto/api.proto +0 -0
  174. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal_proto/api_grpc.py +0 -0
  175. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal_proto/api_pb2.py +0 -0
  176. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal_proto/api_pb2.pyi +0 -0
  177. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal_proto/api_pb2_grpc.py +0 -0
  178. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal_proto/api_pb2_grpc.pyi +0 -0
  179. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal_proto/modal_api_grpc.py +0 -0
  180. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal_proto/modal_options_grpc.py +0 -0
  181. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal_proto/options.proto +0 -0
  182. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal_proto/options_grpc.py +0 -0
  183. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal_proto/options_pb2.py +0 -0
  184. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal_proto/options_pb2.pyi +0 -0
  185. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal_proto/options_pb2_grpc.py +0 -0
  186. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal_proto/options_pb2_grpc.pyi +0 -0
  187. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal_proto/py.typed +0 -0
  188. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/modal_version/__main__.py +0 -0
  189. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/pyproject.toml +0 -0
  190. {modal-1.1.5.dev20 → modal-1.1.5.dev22}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.1.5.dev20
3
+ Version: 1.1.5.dev22
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License: Apache-2.0
@@ -6,7 +6,7 @@ import textwrap
6
6
  import time
7
7
  import typing
8
8
  import warnings
9
- from collections.abc import AsyncGenerator, Sequence, Sized
9
+ from collections.abc import AsyncGenerator, Collection, Sequence, Sized
10
10
  from dataclasses import dataclass
11
11
  from pathlib import PurePosixPath
12
12
  from typing import TYPE_CHECKING, Any, AsyncIterator, Callable, Optional, Union
@@ -597,7 +597,7 @@ class _FunctionSpec:
597
597
 
598
598
  image: Optional[_Image]
599
599
  mounts: Sequence[_Mount]
600
- secrets: Sequence[_Secret]
600
+ secrets: Collection[_Secret]
601
601
  network_file_systems: dict[Union[str, PurePosixPath], _NetworkFileSystem]
602
602
  volumes: dict[Union[str, PurePosixPath], Union[_Volume, _CloudBucketMount]]
603
603
  # TODO(irfansharif): Somehow assert that it's the first kind, in sandboxes
@@ -661,7 +661,8 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
661
661
  info: FunctionInfo,
662
662
  app,
663
663
  image: _Image,
664
- secrets: Sequence[_Secret] = (),
664
+ env: Optional[dict[str, Optional[str]]] = None,
665
+ secrets: Optional[Collection[_Secret]] = None,
665
666
  schedule: Optional[Schedule] = None,
666
667
  is_generator: bool = False,
667
668
  gpu: Union[GPU_T, list[GPU_T]] = None,
@@ -701,7 +702,10 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
701
702
  _experimental_proxy_ip: Optional[str] = None,
702
703
  _experimental_custom_scaling_factor: Optional[float] = None,
703
704
  ) -> "_Function":
704
- """mdmd:hidden"""
705
+ """mdmd:hidden
706
+
707
+ Note: This is not intended to be public API.
708
+ """
705
709
  # Needed to avoid circular imports
706
710
  from ._partial_function import _find_partial_methods_for_user_cls, _PartialFunctionFlags
707
711
 
@@ -736,6 +740,10 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
736
740
  if is_generator:
737
741
  raise InvalidError("Generator functions do not support retries.")
738
742
 
743
+ secrets = secrets or []
744
+ if env:
745
+ secrets = [*secrets, _Secret.from_dict(env)]
746
+
739
747
  function_spec = _FunctionSpec(
740
748
  mounts=all_mounts,
741
749
  secrets=secrets,
@@ -1,7 +1,7 @@
1
1
  # Copyright Modal Labs 2022
2
2
  import inspect
3
3
  import typing
4
- from collections.abc import AsyncGenerator, Coroutine, Sequence
4
+ from collections.abc import AsyncGenerator, Collection, Coroutine, Sequence
5
5
  from pathlib import PurePosixPath
6
6
  from textwrap import dedent
7
7
  from typing import (
@@ -616,7 +616,8 @@ class _App:
616
616
  *,
617
617
  image: Optional[_Image] = None, # The image to run as the container for the function
618
618
  schedule: Optional[Schedule] = None, # An optional Modal Schedule for the function
619
- secrets: Sequence[_Secret] = (), # Optional Modal Secret objects with environment variables for the container
619
+ env: Optional[dict[str, Optional[str]]] = None, # Environment variables to set in the container
620
+ secrets: Optional[Collection[_Secret]] = None, # Secrets to inject into the container as environment variables
620
621
  gpu: Union[
621
622
  GPU_T, list[GPU_T]
622
623
  ] = None, # GPU request as string ("any", "T4", ...), object (`modal.GPU.A100()`, ...), or a list of either
@@ -694,6 +695,9 @@ class _App:
694
695
  if allow_cross_region_volumes is not None:
695
696
  deprecation_warning((2025, 4, 23), "The `allow_cross_region_volumes` parameter no longer has any effect.")
696
697
 
698
+ secrets = secrets or []
699
+ if env:
700
+ secrets = [*secrets, _Secret.from_dict(env)]
697
701
  secrets = [*self._secrets, *secrets]
698
702
 
699
703
  def wrapped(
@@ -846,7 +850,8 @@ class _App:
846
850
  _warn_parentheses_missing=None, # mdmd:line-hidden
847
851
  *,
848
852
  image: Optional[_Image] = None, # The image to run as the container for the function
849
- secrets: Sequence[_Secret] = (), # Optional Modal Secret objects with environment variables for the container
853
+ env: Optional[dict[str, Optional[str]]] = None, # Environment variables to set in the container
854
+ secrets: Optional[Collection[_Secret]] = None, # Secrets to inject into the container as environment variables
850
855
  gpu: Union[
851
856
  GPU_T, list[GPU_T]
852
857
  ] = None, # GPU request as string ("any", "T4", ...), object (`modal.GPU.A100()`, ...), or a list of either
@@ -920,6 +925,10 @@ class _App:
920
925
  if allow_cross_region_volumes is not None:
921
926
  deprecation_warning((2025, 4, 23), "The `allow_cross_region_volumes` parameter no longer has any effect.")
922
927
 
928
+ secrets = secrets or []
929
+ if env:
930
+ secrets = [*secrets, _Secret.from_dict(env)]
931
+
923
932
  def wrapper(wrapped_cls: Union[CLS_T, _PartialFunction]) -> CLS_T:
924
933
  # Check if the decorated object is a class
925
934
  if isinstance(wrapped_cls, _PartialFunction):
@@ -391,7 +391,8 @@ class _App:
391
391
  *,
392
392
  image: typing.Optional[modal.image._Image] = None,
393
393
  schedule: typing.Optional[modal.schedule.Schedule] = None,
394
- secrets: collections.abc.Sequence[modal.secret._Secret] = (),
394
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
395
+ secrets: typing.Optional[collections.abc.Collection[modal.secret._Secret]] = None,
395
396
  gpu: typing.Union[None, str, modal.gpu._GPUConfig, list[typing.Union[None, str, modal.gpu._GPUConfig]]] = None,
396
397
  serialized: bool = False,
397
398
  network_file_systems: dict[
@@ -445,7 +446,8 @@ class _App:
445
446
  _warn_parentheses_missing=None,
446
447
  *,
447
448
  image: typing.Optional[modal.image._Image] = None,
448
- secrets: collections.abc.Sequence[modal.secret._Secret] = (),
449
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
450
+ secrets: typing.Optional[collections.abc.Collection[modal.secret._Secret]] = None,
449
451
  gpu: typing.Union[None, str, modal.gpu._GPUConfig, list[typing.Union[None, str, modal.gpu._GPUConfig]]] = None,
450
452
  serialized: bool = False,
451
453
  network_file_systems: dict[
@@ -996,7 +998,8 @@ class App:
996
998
  *,
997
999
  image: typing.Optional[modal.image.Image] = None,
998
1000
  schedule: typing.Optional[modal.schedule.Schedule] = None,
999
- secrets: collections.abc.Sequence[modal.secret.Secret] = (),
1001
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
1002
+ secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
1000
1003
  gpu: typing.Union[None, str, modal.gpu._GPUConfig, list[typing.Union[None, str, modal.gpu._GPUConfig]]] = None,
1001
1004
  serialized: bool = False,
1002
1005
  network_file_systems: dict[
@@ -1050,7 +1053,8 @@ class App:
1050
1053
  _warn_parentheses_missing=None,
1051
1054
  *,
1052
1055
  image: typing.Optional[modal.image.Image] = None,
1053
- secrets: collections.abc.Sequence[modal.secret.Secret] = (),
1056
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
1057
+ secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
1054
1058
  gpu: typing.Union[None, str, modal.gpu._GPUConfig, list[typing.Union[None, str, modal.gpu._GPUConfig]]] = None,
1055
1059
  serialized: bool = False,
1056
1060
  network_file_systems: dict[
@@ -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.5.dev20",
36
+ version: str = "1.1.5.dev22",
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.5.dev20",
167
+ version: str = "1.1.5.dev22",
168
168
  ):
169
169
  """mdmd:hidden
170
170
  The Modal client object is not intended to be instantiated directly by users.
@@ -81,7 +81,7 @@ def _get_class_constructor_signature(user_cls: type) -> inspect.Signature:
81
81
  @dataclasses.dataclass()
82
82
  class _ServiceOptions:
83
83
  # Note that default values should always be "untruthy" so we can detect when they are not set
84
- secrets: typing.Collection[_Secret] = ()
84
+ secrets: Collection[_Secret] = ()
85
85
  validated_volumes: typing.Sequence[tuple[str, _Volume]] = ()
86
86
  resources: Optional[api_pb2.Resources] = None
87
87
  retry_policy: Optional[api_pb2.FunctionRetryPolicy] = None
@@ -686,7 +686,8 @@ More information on class parameterization can be found here: https://modal.com/
686
686
  cpu: Optional[Union[float, tuple[float, float]]] = None,
687
687
  memory: Optional[Union[int, tuple[int, int]]] = None,
688
688
  gpu: GPU_T = None,
689
- secrets: Collection[_Secret] = (),
689
+ env: Optional[dict[str, Optional[str]]] = None,
690
+ secrets: Optional[Collection[_Secret]] = None,
690
691
  volumes: dict[Union[str, os.PathLike], _Volume] = {},
691
692
  retries: Optional[Union[int, Retries]] = None,
692
693
  max_containers: Optional[int] = None, # Limit on the number of containers that can be concurrently running.
@@ -761,6 +762,10 @@ More information on class parameterization can be found here: https://modal.com/
761
762
  cls = _Cls._from_loader(_load_from_base, rep=f"{self._name}.with_options(...)", is_another_app=True, deps=_deps)
762
763
  cls._initialize_from_other(self)
763
764
 
765
+ secrets = secrets or []
766
+ if env:
767
+ secrets = [*secrets, _Secret.from_dict(env)]
768
+
764
769
  new_options = _ServiceOptions(
765
770
  secrets=secrets,
766
771
  validated_volumes=validate_volumes(volumes),
@@ -24,9 +24,9 @@ def _use_annotation_parameters(user_cls: type) -> bool: ...
24
24
  def _get_class_constructor_signature(user_cls: type) -> inspect.Signature: ...
25
25
 
26
26
  class _ServiceOptions:
27
- """_ServiceOptions(secrets: Collection[modal.secret._Secret] = (), validated_volumes: Sequence[tuple[str, modal.volume._Volume]] = (), resources: Optional[modal_proto.api_pb2.Resources] = None, retry_policy: Optional[modal_proto.api_pb2.FunctionRetryPolicy] = None, max_containers: Optional[int] = None, buffer_containers: Optional[int] = None, scaledown_window: Optional[int] = None, timeout_secs: Optional[int] = None, max_concurrent_inputs: Optional[int] = None, target_concurrent_inputs: Optional[int] = None, batch_max_size: Optional[int] = None, batch_wait_ms: Optional[int] = None, scheduler_placement: Optional[modal_proto.api_pb2.SchedulerPlacement] = None, cloud: Optional[str] = None)"""
27
+ """_ServiceOptions(secrets: collections.abc.Collection[modal.secret._Secret] = (), validated_volumes: Sequence[tuple[str, modal.volume._Volume]] = (), resources: Optional[modal_proto.api_pb2.Resources] = None, retry_policy: Optional[modal_proto.api_pb2.FunctionRetryPolicy] = None, max_containers: Optional[int] = None, buffer_containers: Optional[int] = None, scaledown_window: Optional[int] = None, timeout_secs: Optional[int] = None, max_concurrent_inputs: Optional[int] = None, target_concurrent_inputs: Optional[int] = None, batch_max_size: Optional[int] = None, batch_wait_ms: Optional[int] = None, scheduler_placement: Optional[modal_proto.api_pb2.SchedulerPlacement] = None, cloud: Optional[str] = None)"""
28
28
 
29
- secrets: typing.Collection[modal.secret._Secret]
29
+ secrets: collections.abc.Collection[modal.secret._Secret]
30
30
  validated_volumes: typing.Sequence[tuple[str, modal.volume._Volume]]
31
31
  resources: typing.Optional[modal_proto.api_pb2.Resources]
32
32
  retry_policy: typing.Optional[modal_proto.api_pb2.FunctionRetryPolicy]
@@ -50,7 +50,7 @@ class _ServiceOptions:
50
50
 
51
51
  def __init__(
52
52
  self,
53
- secrets: typing.Collection[modal.secret._Secret] = (),
53
+ secrets: collections.abc.Collection[modal.secret._Secret] = (),
54
54
  validated_volumes: typing.Sequence[tuple[str, modal.volume._Volume]] = (),
55
55
  resources: typing.Optional[modal_proto.api_pb2.Resources] = None,
56
56
  retry_policy: typing.Optional[modal_proto.api_pb2.FunctionRetryPolicy] = None,
@@ -396,7 +396,8 @@ class _Cls(modal._object._Object):
396
396
  cpu: typing.Union[float, tuple[float, float], None] = None,
397
397
  memory: typing.Union[int, tuple[int, int], None] = None,
398
398
  gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
399
- secrets: collections.abc.Collection[modal.secret._Secret] = (),
399
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
400
+ secrets: typing.Optional[collections.abc.Collection[modal.secret._Secret]] = None,
400
401
  volumes: dict[typing.Union[str, os.PathLike], modal.volume._Volume] = {},
401
402
  retries: typing.Union[int, modal.retries.Retries, None] = None,
402
403
  max_containers: typing.Optional[int] = None,
@@ -574,7 +575,8 @@ class Cls(modal.object.Object):
574
575
  cpu: typing.Union[float, tuple[float, float], None] = None,
575
576
  memory: typing.Union[int, tuple[int, int], None] = None,
576
577
  gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
577
- secrets: collections.abc.Collection[modal.secret.Secret] = (),
578
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
579
+ secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
578
580
  volumes: dict[typing.Union[str, os.PathLike], modal.volume.Volume] = {},
579
581
  retries: typing.Union[int, modal.retries.Retries, None] = None,
580
582
  max_containers: typing.Optional[int] = None,
@@ -68,7 +68,8 @@ class Function(
68
68
  info: modal._utils.function_utils.FunctionInfo,
69
69
  app,
70
70
  image: modal.image.Image,
71
- secrets: collections.abc.Sequence[modal.secret.Secret] = (),
71
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
72
+ secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
72
73
  schedule: typing.Optional[modal.schedule.Schedule] = None,
73
74
  is_generator: bool = False,
74
75
  gpu: typing.Union[None, str, modal.gpu._GPUConfig, list[typing.Union[None, str, modal.gpu._GPUConfig]]] = None,
@@ -111,7 +112,10 @@ class Function(
111
112
  _experimental_proxy_ip: typing.Optional[str] = None,
112
113
  _experimental_custom_scaling_factor: typing.Optional[float] = None,
113
114
  ) -> Function:
114
- """mdmd:hidden"""
115
+ """mdmd:hidden
116
+
117
+ Note: This is not intended to be public API.
118
+ """
115
119
  ...
116
120
 
117
121
  def _bind_parameters(
@@ -7,7 +7,7 @@ import shlex
7
7
  import sys
8
8
  import typing
9
9
  import warnings
10
- from collections.abc import Sequence
10
+ from collections.abc import Collection, Sequence
11
11
  from dataclasses import dataclass
12
12
  from inspect import isfunction
13
13
  from pathlib import Path, PurePosixPath
@@ -491,7 +491,7 @@ class _Image(_Object, type_prefix="im"):
491
491
  *,
492
492
  base_images: Optional[dict[str, "_Image"]] = None,
493
493
  dockerfile_function: Optional[Callable[[ImageBuilderVersion], DockerfileSpec]] = None,
494
- secrets: Optional[Sequence[_Secret]] = None,
494
+ secrets: Optional[Collection[_Secret]] = None,
495
495
  gpu_config: Optional[api_pb2.GPUConfig] = None,
496
496
  build_function: Optional["modal._functions._Function"] = None,
497
497
  build_function_input: Optional[api_pb2.FunctionInput] = None,
@@ -877,7 +877,8 @@ class _Image(_Object, type_prefix="im"):
877
877
  pre: bool = False, # Passes --pre (allow pre-releases) to pip install
878
878
  extra_options: str = "", # Additional options to pass to pip install, e.g. "--no-build-isolation --no-clean"
879
879
  force_build: bool = False, # Ignore cached builds, similar to 'docker build --no-cache'
880
- secrets: Sequence[_Secret] = [],
880
+ env: Optional[dict[str, Optional[str]]] = None,
881
+ secrets: Optional[Collection[_Secret]] = None,
881
882
  gpu: GPU_T = None,
882
883
  ) -> "_Image":
883
884
  """Install a list of Python packages using pip.
@@ -924,6 +925,10 @@ class _Image(_Object, type_prefix="im"):
924
925
  commands = [cmd.strip() for cmd in commands]
925
926
  return DockerfileSpec(commands=commands, context_files={})
926
927
 
928
+ secrets = secrets or []
929
+ if env:
930
+ secrets = [*secrets, _Secret.from_dict(env)]
931
+
927
932
  gpu_config = parse_gpu_config(gpu)
928
933
  return _Image._from_args(
929
934
  base_images={"base": self},
@@ -943,7 +948,8 @@ class _Image(_Object, type_prefix="im"):
943
948
  pre: bool = False, # Passes --pre (allow pre-releases) to pip install
944
949
  extra_options: str = "", # Additional options to pass to pip install, e.g. "--no-build-isolation --no-clean"
945
950
  gpu: GPU_T = None,
946
- secrets: Sequence[_Secret] = [],
951
+ env: Optional[dict[str, Optional[str]]] = None, # Environment variables to set in the container
952
+ secrets: Optional[Collection[_Secret]] = None, # Secrets to inject into the container as environment variables
947
953
  force_build: bool = False, # Ignore cached builds, similar to 'docker build --no-cache'
948
954
  ) -> "_Image":
949
955
  """
@@ -977,12 +983,16 @@ class _Image(_Object, type_prefix="im"):
977
983
  )
978
984
  ```
979
985
  """
986
+
980
987
  if not secrets:
981
988
  raise InvalidError(
982
989
  "No secrets provided to function. "
983
990
  "Installing private packages requires tokens to be passed via modal.Secret objects."
984
991
  )
985
992
 
993
+ if env:
994
+ secrets = [*secrets, _Secret.from_dict(env)]
995
+
986
996
  invalid_repos = []
987
997
  install_urls = []
988
998
  for repo_ref in repositories:
@@ -1044,11 +1054,16 @@ class _Image(_Object, type_prefix="im"):
1044
1054
  pre: bool = False, # Passes --pre (allow pre-releases) to pip install
1045
1055
  extra_options: str = "", # Additional options to pass to pip install, e.g. "--no-build-isolation --no-clean"
1046
1056
  force_build: bool = False, # Ignore cached builds, similar to 'docker build --no-cache'
1047
- secrets: Sequence[_Secret] = [],
1057
+ env: Optional[dict[str, Optional[str]]] = None,
1058
+ secrets: Optional[Collection[_Secret]] = None,
1048
1059
  gpu: GPU_T = None,
1049
1060
  ) -> "_Image":
1050
1061
  """Install a list of Python packages from a local `requirements.txt` file."""
1051
1062
 
1063
+ secrets = secrets or []
1064
+ if env:
1065
+ secrets = [*secrets, _Secret.from_dict(env)]
1066
+
1052
1067
  def build_dockerfile(version: ImageBuilderVersion) -> DockerfileSpec:
1053
1068
  requirements_txt_path = os.path.expanduser(requirements_txt)
1054
1069
  context_files = {"/.requirements.txt": requirements_txt_path}
@@ -1085,7 +1100,8 @@ class _Image(_Object, type_prefix="im"):
1085
1100
  pre: bool = False, # Passes --pre (allow pre-releases) to pip install
1086
1101
  extra_options: str = "", # Additional options to pass to pip install, e.g. "--no-build-isolation --no-clean"
1087
1102
  force_build: bool = False, # Ignore cached builds, similar to 'docker build --no-cache'
1088
- secrets: Sequence[_Secret] = [],
1103
+ env: Optional[dict[str, Optional[str]]] = None,
1104
+ secrets: Optional[Collection[_Secret]] = None,
1089
1105
  gpu: GPU_T = None,
1090
1106
  ) -> "_Image":
1091
1107
  """Install dependencies specified by a local `pyproject.toml` file.
@@ -1096,6 +1112,10 @@ class _Image(_Object, type_prefix="im"):
1096
1112
  all of the packages in each listed section are installed as well.
1097
1113
  """
1098
1114
 
1115
+ secrets = secrets or []
1116
+ if env:
1117
+ secrets = [*secrets, _Secret.from_dict(env)]
1118
+
1099
1119
  def build_dockerfile(version: ImageBuilderVersion) -> DockerfileSpec:
1100
1120
  # Defer toml import so we don't need it in the container runtime environment
1101
1121
  import toml
@@ -1147,7 +1167,8 @@ class _Image(_Object, type_prefix="im"):
1147
1167
  extra_options: str = "", # Additional options to pass to pip install, e.g. "--no-build-isolation"
1148
1168
  force_build: bool = False, # Ignore cached builds, similar to 'docker build --no-cache'
1149
1169
  uv_version: Optional[str] = None, # uv version to use
1150
- secrets: Sequence[_Secret] = [],
1170
+ env: Optional[dict[str, Optional[str]]] = None,
1171
+ secrets: Optional[Collection[_Secret]] = None,
1151
1172
  gpu: GPU_T = None,
1152
1173
  ) -> "_Image":
1153
1174
  """Install a list of Python packages using uv pip install.
@@ -1166,6 +1187,11 @@ class _Image(_Object, type_prefix="im"):
1166
1187
 
1167
1188
  Added in v1.1.0.
1168
1189
  """
1190
+
1191
+ secrets = secrets or []
1192
+ if env:
1193
+ secrets = [*secrets, _Secret.from_dict(env)]
1194
+
1169
1195
  pkgs = _flatten_str_args("uv_pip_install", "packages", packages)
1170
1196
 
1171
1197
  if requirements is None or isinstance(requirements, list):
@@ -1261,7 +1287,8 @@ class _Image(_Object, type_prefix="im"):
1261
1287
  poetry_version: Optional[str] = "latest", # Version of poetry to install, or None to skip installation
1262
1288
  # If set to True, use old installer. See https://github.com/python-poetry/poetry/issues/3336
1263
1289
  old_installer: bool = False,
1264
- secrets: Sequence[_Secret] = [],
1290
+ env: Optional[dict[str, Optional[str]]] = None,
1291
+ secrets: Optional[Collection[_Secret]] = None,
1265
1292
  gpu: GPU_T = None,
1266
1293
  ) -> "_Image":
1267
1294
  """Install poetry *dependencies* specified by a local `pyproject.toml` file.
@@ -1277,6 +1304,10 @@ class _Image(_Object, type_prefix="im"):
1277
1304
  version, with versions 2024.10 and earlier limiting poetry to 1.x.
1278
1305
  """
1279
1306
 
1307
+ secrets = secrets or []
1308
+ if env:
1309
+ secrets = [*secrets, _Secret.from_dict(env)]
1310
+
1280
1311
  def build_dockerfile(version: ImageBuilderVersion) -> DockerfileSpec:
1281
1312
  context_files = {"/.pyproject.toml": os.path.expanduser(poetry_pyproject_toml)}
1282
1313
 
@@ -1346,7 +1377,8 @@ class _Image(_Object, type_prefix="im"):
1346
1377
  frozen: bool = True, # If True, then we run `uv sync --frozen` when a uv.lock file is present
1347
1378
  extra_options: str = "", # Extra options to pass to `uv sync`
1348
1379
  uv_version: Optional[str] = None, # uv version to use
1349
- secrets: Sequence[_Secret] = [],
1380
+ env: Optional[dict[str, Optional[str]]] = None,
1381
+ secrets: Optional[Collection[_Secret]] = None,
1350
1382
  gpu: GPU_T = None,
1351
1383
  ) -> "_Image":
1352
1384
  """Creates a virtual environment with the dependencies in a uv managed project with `uv sync`.
@@ -1362,6 +1394,10 @@ class _Image(_Object, type_prefix="im"):
1362
1394
  Added in v1.1.0.
1363
1395
  """
1364
1396
 
1397
+ secrets = secrets or []
1398
+ if env:
1399
+ secrets = [*secrets, _Secret.from_dict(env)]
1400
+
1365
1401
  def _normalize_items(items, name) -> list[str]:
1366
1402
  if items is None:
1367
1403
  return []
@@ -1494,7 +1530,8 @@ class _Image(_Object, type_prefix="im"):
1494
1530
  self,
1495
1531
  *dockerfile_commands: Union[str, list[str]],
1496
1532
  context_files: dict[str, str] = {},
1497
- secrets: Sequence[_Secret] = [],
1533
+ env: Optional[dict[str, Optional[str]]] = None,
1534
+ secrets: Optional[Collection[_Secret]] = None,
1498
1535
  gpu: GPU_T = None,
1499
1536
  context_mount: Optional[_Mount] = None, # Deprecated: the context is now inferred
1500
1537
  context_dir: Optional[Union[Path, str]] = None, # Context for relative COPY commands
@@ -1552,6 +1589,10 @@ class _Image(_Object, type_prefix="im"):
1552
1589
  if not cmds:
1553
1590
  return self
1554
1591
 
1592
+ secrets = secrets or []
1593
+ if env:
1594
+ secrets = [*secrets, _Secret.from_dict(env)]
1595
+
1555
1596
  def build_dockerfile(version: ImageBuilderVersion) -> DockerfileSpec:
1556
1597
  return DockerfileSpec(commands=["FROM base", *cmds], context_files=context_files)
1557
1598
 
@@ -1595,11 +1636,17 @@ class _Image(_Object, type_prefix="im"):
1595
1636
  def run_commands(
1596
1637
  self,
1597
1638
  *commands: Union[str, list[str]],
1598
- secrets: Sequence[_Secret] = [],
1639
+ env: Optional[dict[str, Optional[str]]] = None,
1640
+ secrets: Optional[Collection[_Secret]] = None,
1599
1641
  gpu: GPU_T = None,
1600
1642
  force_build: bool = False, # Ignore cached builds, similar to 'docker build --no-cache'
1601
1643
  ) -> "_Image":
1602
1644
  """Extend an image with a list of shell commands to run."""
1645
+
1646
+ secrets = secrets or []
1647
+ if env:
1648
+ secrets = [*secrets, _Secret.from_dict(env)]
1649
+
1603
1650
  cmds = _flatten_str_args("run_commands", "commands", commands)
1604
1651
  if not cmds:
1605
1652
  return self
@@ -1658,10 +1705,16 @@ class _Image(_Object, type_prefix="im"):
1658
1705
  # A list of Conda channels, eg. ["conda-forge", "nvidia"].
1659
1706
  channels: list[str] = [],
1660
1707
  force_build: bool = False, # Ignore cached builds, similar to 'docker build --no-cache'
1661
- secrets: Sequence[_Secret] = [],
1708
+ env: Optional[dict[str, Optional[str]]] = None,
1709
+ secrets: Optional[Collection[_Secret]] = None,
1662
1710
  gpu: GPU_T = None,
1663
1711
  ) -> "_Image":
1664
1712
  """Install a list of additional packages using micromamba."""
1713
+
1714
+ secrets = secrets or []
1715
+ if env:
1716
+ secrets = [*secrets, _Secret.from_dict(env)]
1717
+
1665
1718
  pkgs = _flatten_str_args("micromamba_install", "packages", packages)
1666
1719
  if not pkgs and spec_file is None:
1667
1720
  return self
@@ -1909,7 +1962,8 @@ class _Image(_Object, type_prefix="im"):
1909
1962
  context_mount: Optional[_Mount] = None, # Deprecated: the context is now inferred
1910
1963
  force_build: bool = False, # Ignore cached builds, similar to 'docker build --no-cache'
1911
1964
  context_dir: Optional[Union[Path, str]] = None, # Context for relative COPY commands
1912
- secrets: Sequence[_Secret] = [],
1965
+ env: Optional[dict[str, Optional[str]]] = None,
1966
+ secrets: Optional[Collection[_Secret]] = None,
1913
1967
  gpu: GPU_T = None,
1914
1968
  add_python: Optional[str] = None,
1915
1969
  build_args: dict[str, str] = {},
@@ -1964,6 +2018,11 @@ class _Image(_Object, type_prefix="im"):
1964
2018
  )
1965
2019
  ```
1966
2020
  """
2021
+
2022
+ secrets = secrets or []
2023
+ if env:
2024
+ secrets = [*secrets, _Secret.from_dict(env)]
2025
+
1967
2026
  if context_mount is not None:
1968
2027
  deprecation_warning(
1969
2028
  (2025, 1, 13),
@@ -2078,7 +2137,8 @@ class _Image(_Object, type_prefix="im"):
2078
2137
  self,
2079
2138
  *packages: Union[str, list[str]], # A list of packages, e.g. ["ssh", "libpq-dev"]
2080
2139
  force_build: bool = False, # Ignore cached builds, similar to 'docker build --no-cache'
2081
- secrets: Sequence[_Secret] = [],
2140
+ env: Optional[dict[str, Optional[str]]] = None,
2141
+ secrets: Optional[Collection[_Secret]] = None,
2082
2142
  gpu: GPU_T = None,
2083
2143
  ) -> "_Image":
2084
2144
  """Install a list of Debian packages using `apt`.
@@ -2103,6 +2163,10 @@ class _Image(_Object, type_prefix="im"):
2103
2163
  ]
2104
2164
  return DockerfileSpec(commands=commands, context_files={})
2105
2165
 
2166
+ secrets = secrets or []
2167
+ if env:
2168
+ secrets = [*secrets, _Secret.from_dict(env)]
2169
+
2106
2170
  return _Image._from_args(
2107
2171
  base_images={"base": self},
2108
2172
  dockerfile_function=build_dockerfile,
@@ -2115,7 +2179,8 @@ class _Image(_Object, type_prefix="im"):
2115
2179
  self,
2116
2180
  raw_f: Callable[..., Any],
2117
2181
  *,
2118
- secrets: Sequence[_Secret] = (), # Optional Modal Secret objects with environment variables for the container
2182
+ env: Optional[dict[str, Optional[str]]] = None, # Environment variables to set in the container
2183
+ secrets: Optional[Collection[_Secret]] = None, # Secrets to inject into the container as environment variables
2119
2184
  volumes: dict[Union[str, PurePosixPath], Union[_Volume, _CloudBucketMount]] = {}, # Volume mount paths
2120
2185
  network_file_systems: dict[Union[str, PurePosixPath], _NetworkFileSystem] = {}, # NFS mount paths
2121
2186
  gpu: Union[GPU_T, list[GPU_T]] = None, # Requested GPU or or list of acceptable GPUs( e.g. ["A10", "A100"])
@@ -2157,6 +2222,11 @@ class _Image(_Object, type_prefix="im"):
2157
2222
  )
2158
2223
  ```
2159
2224
  """
2225
+
2226
+ secrets = secrets or []
2227
+ if env:
2228
+ secrets = [*secrets, _Secret.from_dict(env)]
2229
+
2160
2230
  from ._functions import _Function
2161
2231
 
2162
2232
  if not callable(raw_f):