modal 1.1.5.dev20__py3-none-any.whl → 1.1.5.dev22__py3-none-any.whl

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.

modal/_functions.py CHANGED
@@ -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,
modal/app.py CHANGED
@@ -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):
modal/app.pyi CHANGED
@@ -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[
modal/client.pyi CHANGED
@@ -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.
modal/cls.py CHANGED
@@ -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),
modal/cls.pyi CHANGED
@@ -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,
modal/functions.pyi CHANGED
@@ -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(
modal/image.py CHANGED
@@ -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):
modal/image.pyi CHANGED
@@ -166,7 +166,7 @@ class _Image(modal._object._Object):
166
166
  [typing.Literal["2023.12", "2024.04", "2024.10", "2025.06", "PREVIEW"]], DockerfileSpec
167
167
  ]
168
168
  ] = None,
169
- secrets: typing.Optional[collections.abc.Sequence[modal.secret._Secret]] = None,
169
+ secrets: typing.Optional[collections.abc.Collection[modal.secret._Secret]] = None,
170
170
  gpu_config: typing.Optional[modal_proto.api_pb2.GPUConfig] = None,
171
171
  build_function: typing.Optional[modal._functions._Function] = None,
172
172
  build_function_input: typing.Optional[modal_proto.api_pb2.FunctionInput] = None,
@@ -327,7 +327,8 @@ class _Image(modal._object._Object):
327
327
  pre: bool = False,
328
328
  extra_options: str = "",
329
329
  force_build: bool = False,
330
- secrets: collections.abc.Sequence[modal.secret._Secret] = [],
330
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
331
+ secrets: typing.Optional[collections.abc.Collection[modal.secret._Secret]] = None,
331
332
  gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
332
333
  ) -> _Image:
333
334
  """Install a list of Python packages using pip.
@@ -369,7 +370,8 @@ class _Image(modal._object._Object):
369
370
  pre: bool = False,
370
371
  extra_options: str = "",
371
372
  gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
372
- secrets: collections.abc.Sequence[modal.secret._Secret] = [],
373
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
374
+ secrets: typing.Optional[collections.abc.Collection[modal.secret._Secret]] = None,
373
375
  force_build: bool = False,
374
376
  ) -> _Image:
375
377
  """Install a list of Python packages from private git repositories using pip.
@@ -414,7 +416,8 @@ class _Image(modal._object._Object):
414
416
  pre: bool = False,
415
417
  extra_options: str = "",
416
418
  force_build: bool = False,
417
- secrets: collections.abc.Sequence[modal.secret._Secret] = [],
419
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
420
+ secrets: typing.Optional[collections.abc.Collection[modal.secret._Secret]] = None,
418
421
  gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
419
422
  ) -> _Image:
420
423
  """Install a list of Python packages from a local `requirements.txt` file."""
@@ -431,7 +434,8 @@ class _Image(modal._object._Object):
431
434
  pre: bool = False,
432
435
  extra_options: str = "",
433
436
  force_build: bool = False,
434
- secrets: collections.abc.Sequence[modal.secret._Secret] = [],
437
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
438
+ secrets: typing.Optional[collections.abc.Collection[modal.secret._Secret]] = None,
435
439
  gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
436
440
  ) -> _Image:
437
441
  """Install dependencies specified by a local `pyproject.toml` file.
@@ -454,7 +458,8 @@ class _Image(modal._object._Object):
454
458
  extra_options: str = "",
455
459
  force_build: bool = False,
456
460
  uv_version: typing.Optional[str] = None,
457
- secrets: collections.abc.Sequence[modal.secret._Secret] = [],
461
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
462
+ secrets: typing.Optional[collections.abc.Collection[modal.secret._Secret]] = None,
458
463
  gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
459
464
  ) -> _Image:
460
465
  """Install a list of Python packages using uv pip install.
@@ -487,7 +492,8 @@ class _Image(modal._object._Object):
487
492
  only: list[str] = [],
488
493
  poetry_version: typing.Optional[str] = "latest",
489
494
  old_installer: bool = False,
490
- secrets: collections.abc.Sequence[modal.secret._Secret] = [],
495
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
496
+ secrets: typing.Optional[collections.abc.Collection[modal.secret._Secret]] = None,
491
497
  gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
492
498
  ) -> _Image:
493
499
  """Install poetry *dependencies* specified by a local `pyproject.toml` file.
@@ -514,7 +520,8 @@ class _Image(modal._object._Object):
514
520
  frozen: bool = True,
515
521
  extra_options: str = "",
516
522
  uv_version: typing.Optional[str] = None,
517
- secrets: collections.abc.Sequence[modal.secret._Secret] = [],
523
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
524
+ secrets: typing.Optional[collections.abc.Collection[modal.secret._Secret]] = None,
518
525
  gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
519
526
  ) -> _Image:
520
527
  """Creates a virtual environment with the dependencies in a uv managed project with `uv sync`.
@@ -535,7 +542,8 @@ class _Image(modal._object._Object):
535
542
  self,
536
543
  *dockerfile_commands: typing.Union[str, list[str]],
537
544
  context_files: dict[str, str] = {},
538
- secrets: collections.abc.Sequence[modal.secret._Secret] = [],
545
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
546
+ secrets: typing.Optional[collections.abc.Collection[modal.secret._Secret]] = None,
539
547
  gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
540
548
  context_mount: typing.Optional[modal.mount._Mount] = None,
541
549
  context_dir: typing.Union[str, pathlib.Path, None] = None,
@@ -597,7 +605,8 @@ class _Image(modal._object._Object):
597
605
  def run_commands(
598
606
  self,
599
607
  *commands: typing.Union[str, list[str]],
600
- secrets: collections.abc.Sequence[modal.secret._Secret] = [],
608
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
609
+ secrets: typing.Optional[collections.abc.Collection[modal.secret._Secret]] = None,
601
610
  gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
602
611
  force_build: bool = False,
603
612
  ) -> _Image:
@@ -615,7 +624,8 @@ class _Image(modal._object._Object):
615
624
  spec_file: typing.Optional[str] = None,
616
625
  channels: list[str] = [],
617
626
  force_build: bool = False,
618
- secrets: collections.abc.Sequence[modal.secret._Secret] = [],
627
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
628
+ secrets: typing.Optional[collections.abc.Collection[modal.secret._Secret]] = None,
619
629
  gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
620
630
  ) -> _Image:
621
631
  """Install a list of additional packages using micromamba."""
@@ -756,7 +766,8 @@ class _Image(modal._object._Object):
756
766
  context_mount: typing.Optional[modal.mount._Mount] = None,
757
767
  force_build: bool = False,
758
768
  context_dir: typing.Union[str, pathlib.Path, None] = None,
759
- secrets: collections.abc.Sequence[modal.secret._Secret] = [],
769
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
770
+ secrets: typing.Optional[collections.abc.Collection[modal.secret._Secret]] = None,
760
771
  gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
761
772
  add_python: typing.Optional[str] = None,
762
773
  build_args: dict[str, str] = {},
@@ -824,7 +835,8 @@ class _Image(modal._object._Object):
824
835
  self,
825
836
  *packages: typing.Union[str, list[str]],
826
837
  force_build: bool = False,
827
- secrets: collections.abc.Sequence[modal.secret._Secret] = [],
838
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
839
+ secrets: typing.Optional[collections.abc.Collection[modal.secret._Secret]] = None,
828
840
  gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
829
841
  ) -> _Image:
830
842
  """Install a list of Debian packages using `apt`.
@@ -841,7 +853,8 @@ class _Image(modal._object._Object):
841
853
  self,
842
854
  raw_f: collections.abc.Callable[..., typing.Any],
843
855
  *,
844
- secrets: collections.abc.Sequence[modal.secret._Secret] = (),
856
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
857
+ secrets: typing.Optional[collections.abc.Collection[modal.secret._Secret]] = None,
845
858
  volumes: dict[
846
859
  typing.Union[str, pathlib.PurePosixPath],
847
860
  typing.Union[modal.volume._Volume, modal.cloud_bucket_mount._CloudBucketMount],
@@ -1008,7 +1021,7 @@ class Image(modal.object.Object):
1008
1021
  [typing.Literal["2023.12", "2024.04", "2024.10", "2025.06", "PREVIEW"]], DockerfileSpec
1009
1022
  ]
1010
1023
  ] = None,
1011
- secrets: typing.Optional[collections.abc.Sequence[modal.secret.Secret]] = None,
1024
+ secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
1012
1025
  gpu_config: typing.Optional[modal_proto.api_pb2.GPUConfig] = None,
1013
1026
  build_function: typing.Optional[modal.functions.Function] = None,
1014
1027
  build_function_input: typing.Optional[modal_proto.api_pb2.FunctionInput] = None,
@@ -1178,7 +1191,8 @@ class Image(modal.object.Object):
1178
1191
  pre: bool = False,
1179
1192
  extra_options: str = "",
1180
1193
  force_build: bool = False,
1181
- secrets: collections.abc.Sequence[modal.secret.Secret] = [],
1194
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
1195
+ secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
1182
1196
  gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
1183
1197
  ) -> Image:
1184
1198
  """Install a list of Python packages using pip.
@@ -1220,7 +1234,8 @@ class Image(modal.object.Object):
1220
1234
  pre: bool = False,
1221
1235
  extra_options: str = "",
1222
1236
  gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
1223
- secrets: collections.abc.Sequence[modal.secret.Secret] = [],
1237
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
1238
+ secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
1224
1239
  force_build: bool = False,
1225
1240
  ) -> Image:
1226
1241
  """Install a list of Python packages from private git repositories using pip.
@@ -1265,7 +1280,8 @@ class Image(modal.object.Object):
1265
1280
  pre: bool = False,
1266
1281
  extra_options: str = "",
1267
1282
  force_build: bool = False,
1268
- secrets: collections.abc.Sequence[modal.secret.Secret] = [],
1283
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
1284
+ secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
1269
1285
  gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
1270
1286
  ) -> Image:
1271
1287
  """Install a list of Python packages from a local `requirements.txt` file."""
@@ -1282,7 +1298,8 @@ class Image(modal.object.Object):
1282
1298
  pre: bool = False,
1283
1299
  extra_options: str = "",
1284
1300
  force_build: bool = False,
1285
- secrets: collections.abc.Sequence[modal.secret.Secret] = [],
1301
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
1302
+ secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
1286
1303
  gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
1287
1304
  ) -> Image:
1288
1305
  """Install dependencies specified by a local `pyproject.toml` file.
@@ -1305,7 +1322,8 @@ class Image(modal.object.Object):
1305
1322
  extra_options: str = "",
1306
1323
  force_build: bool = False,
1307
1324
  uv_version: typing.Optional[str] = None,
1308
- secrets: collections.abc.Sequence[modal.secret.Secret] = [],
1325
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
1326
+ secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
1309
1327
  gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
1310
1328
  ) -> Image:
1311
1329
  """Install a list of Python packages using uv pip install.
@@ -1338,7 +1356,8 @@ class Image(modal.object.Object):
1338
1356
  only: list[str] = [],
1339
1357
  poetry_version: typing.Optional[str] = "latest",
1340
1358
  old_installer: bool = False,
1341
- secrets: collections.abc.Sequence[modal.secret.Secret] = [],
1359
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
1360
+ secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
1342
1361
  gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
1343
1362
  ) -> Image:
1344
1363
  """Install poetry *dependencies* specified by a local `pyproject.toml` file.
@@ -1365,7 +1384,8 @@ class Image(modal.object.Object):
1365
1384
  frozen: bool = True,
1366
1385
  extra_options: str = "",
1367
1386
  uv_version: typing.Optional[str] = None,
1368
- secrets: collections.abc.Sequence[modal.secret.Secret] = [],
1387
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
1388
+ secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
1369
1389
  gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
1370
1390
  ) -> Image:
1371
1391
  """Creates a virtual environment with the dependencies in a uv managed project with `uv sync`.
@@ -1386,7 +1406,8 @@ class Image(modal.object.Object):
1386
1406
  self,
1387
1407
  *dockerfile_commands: typing.Union[str, list[str]],
1388
1408
  context_files: dict[str, str] = {},
1389
- secrets: collections.abc.Sequence[modal.secret.Secret] = [],
1409
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
1410
+ secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
1390
1411
  gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
1391
1412
  context_mount: typing.Optional[modal.mount.Mount] = None,
1392
1413
  context_dir: typing.Union[str, pathlib.Path, None] = None,
@@ -1448,7 +1469,8 @@ class Image(modal.object.Object):
1448
1469
  def run_commands(
1449
1470
  self,
1450
1471
  *commands: typing.Union[str, list[str]],
1451
- secrets: collections.abc.Sequence[modal.secret.Secret] = [],
1472
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
1473
+ secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
1452
1474
  gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
1453
1475
  force_build: bool = False,
1454
1476
  ) -> Image:
@@ -1466,7 +1488,8 @@ class Image(modal.object.Object):
1466
1488
  spec_file: typing.Optional[str] = None,
1467
1489
  channels: list[str] = [],
1468
1490
  force_build: bool = False,
1469
- secrets: collections.abc.Sequence[modal.secret.Secret] = [],
1491
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
1492
+ secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
1470
1493
  gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
1471
1494
  ) -> Image:
1472
1495
  """Install a list of additional packages using micromamba."""
@@ -1607,7 +1630,8 @@ class Image(modal.object.Object):
1607
1630
  context_mount: typing.Optional[modal.mount.Mount] = None,
1608
1631
  force_build: bool = False,
1609
1632
  context_dir: typing.Union[str, pathlib.Path, None] = None,
1610
- secrets: collections.abc.Sequence[modal.secret.Secret] = [],
1633
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
1634
+ secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
1611
1635
  gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
1612
1636
  add_python: typing.Optional[str] = None,
1613
1637
  build_args: dict[str, str] = {},
@@ -1675,7 +1699,8 @@ class Image(modal.object.Object):
1675
1699
  self,
1676
1700
  *packages: typing.Union[str, list[str]],
1677
1701
  force_build: bool = False,
1678
- secrets: collections.abc.Sequence[modal.secret.Secret] = [],
1702
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
1703
+ secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
1679
1704
  gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
1680
1705
  ) -> Image:
1681
1706
  """Install a list of Debian packages using `apt`.
@@ -1692,7 +1717,8 @@ class Image(modal.object.Object):
1692
1717
  self,
1693
1718
  raw_f: collections.abc.Callable[..., typing.Any],
1694
1719
  *,
1695
- secrets: collections.abc.Sequence[modal.secret.Secret] = (),
1720
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
1721
+ secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
1696
1722
  volumes: dict[
1697
1723
  typing.Union[str, pathlib.PurePosixPath],
1698
1724
  typing.Union[modal.volume.Volume, modal.cloud_bucket_mount.CloudBucketMount],
modal/sandbox.py CHANGED
@@ -3,7 +3,7 @@ import asyncio
3
3
  import json
4
4
  import os
5
5
  import time
6
- from collections.abc import AsyncGenerator, Sequence
6
+ from collections.abc import AsyncGenerator, Collection, Sequence
7
7
  from dataclasses import dataclass
8
8
  from typing import TYPE_CHECKING, Any, AsyncIterator, Literal, Optional, Union, overload
9
9
 
@@ -133,7 +133,7 @@ class _Sandbox(_Object, type_prefix="sb"):
133
133
  def _new(
134
134
  args: Sequence[str],
135
135
  image: _Image,
136
- secrets: Sequence[_Secret],
136
+ secrets: Collection[_Secret],
137
137
  name: Optional[str] = None,
138
138
  timeout: int = 300,
139
139
  idle_timeout: Optional[int] = None,
@@ -288,7 +288,8 @@ class _Sandbox(_Object, type_prefix="sb"):
288
288
  app: Optional["modal.app._App"] = None,
289
289
  name: Optional[str] = None, # Optionally give the sandbox a name. Unique within an app.
290
290
  image: Optional[_Image] = None, # The image to run as the container for the sandbox.
291
- secrets: Sequence[_Secret] = (), # Environment variables to inject into the sandbox.
291
+ env: Optional[dict[str, Optional[str]]] = None, # Environment variables to set in the Sandbox.
292
+ secrets: Optional[Collection[_Secret]] = None, # Secrets to inject into the Sandbox as environment variables.
292
293
  network_file_systems: dict[Union[str, os.PathLike], _NetworkFileSystem] = {},
293
294
  timeout: int = 300, # Maximum lifetime of the sandbox in seconds.
294
295
  # The amount of time in seconds that a sandbox can be idle before being terminated.
@@ -359,6 +360,10 @@ class _Sandbox(_Object, type_prefix="sb"):
359
360
  "Set the `pty` parameter to `True` instead.",
360
361
  )
361
362
 
363
+ secrets = secrets or []
364
+ if env:
365
+ secrets = [*secrets, _Secret.from_dict(env)]
366
+
362
367
  return await _Sandbox._create(
363
368
  *args,
364
369
  app=app,
@@ -396,7 +401,8 @@ class _Sandbox(_Object, type_prefix="sb"):
396
401
  app: Optional["modal.app._App"] = None,
397
402
  name: Optional[str] = None,
398
403
  image: Optional[_Image] = None,
399
- secrets: Sequence[_Secret] = (),
404
+ env: Optional[dict[str, Optional[str]]] = None,
405
+ secrets: Optional[Collection[_Secret]] = None,
400
406
  mounts: Sequence[_Mount] = (),
401
407
  network_file_systems: dict[Union[str, os.PathLike], _NetworkFileSystem] = {},
402
408
  timeout: int = 300,
@@ -409,9 +415,7 @@ class _Sandbox(_Object, type_prefix="sb"):
409
415
  memory: Optional[Union[int, tuple[int, int]]] = None,
410
416
  block_network: bool = False,
411
417
  cidr_allowlist: Optional[Sequence[str]] = None,
412
- volumes: dict[
413
- Union[str, os.PathLike], Union[_Volume, _CloudBucketMount]
414
- ] = {},
418
+ volumes: dict[Union[str, os.PathLike], Union[_Volume, _CloudBucketMount]] = {},
415
419
  pty: bool = False,
416
420
  encrypted_ports: Sequence[int] = [],
417
421
  h2_ports: Sequence[int] = [],
@@ -419,9 +423,7 @@ class _Sandbox(_Object, type_prefix="sb"):
419
423
  proxy: Optional[_Proxy] = None,
420
424
  experimental_options: Optional[dict[str, bool]] = None,
421
425
  _experimental_enable_snapshot: bool = False,
422
- _experimental_scheduler_placement: Optional[
423
- SchedulerPlacement
424
- ] = None,
426
+ _experimental_scheduler_placement: Optional[SchedulerPlacement] = None,
425
427
  client: Optional[_Client] = None,
426
428
  verbose: bool = False,
427
429
  pty_info: Optional[api_pb2.PTYInfo] = None,
@@ -441,6 +443,10 @@ class _Sandbox(_Object, type_prefix="sb"):
441
443
  if block_network and (encrypted_ports or h2_ports or unencrypted_ports):
442
444
  raise InvalidError("Cannot specify open ports when `block_network` is enabled")
443
445
 
446
+ secrets = secrets or []
447
+ if env:
448
+ secrets = [*secrets, _Secret.from_dict(env)]
449
+
444
450
  # TODO(erikbern): Get rid of the `_new` method and create an already-hydrated object
445
451
  obj = _Sandbox._new(
446
452
  args,
@@ -717,7 +723,8 @@ class _Sandbox(_Object, type_prefix="sb"):
717
723
  stderr: StreamType = StreamType.PIPE,
718
724
  timeout: Optional[int] = None,
719
725
  workdir: Optional[str] = None,
720
- secrets: Sequence[_Secret] = (),
726
+ env: Optional[dict[str, Optional[str]]] = None,
727
+ secrets: Optional[Collection[_Secret]] = None,
721
728
  text: Literal[True] = True,
722
729
  bufsize: Literal[-1, 1] = -1,
723
730
  pty: bool = False,
@@ -733,7 +740,8 @@ class _Sandbox(_Object, type_prefix="sb"):
733
740
  stderr: StreamType = StreamType.PIPE,
734
741
  timeout: Optional[int] = None,
735
742
  workdir: Optional[str] = None,
736
- secrets: Sequence[_Secret] = (),
743
+ env: Optional[dict[str, Optional[str]]] = None,
744
+ secrets: Optional[Collection[_Secret]] = None,
737
745
  text: Literal[False] = False,
738
746
  bufsize: Literal[-1, 1] = -1,
739
747
  pty: bool = False,
@@ -748,7 +756,10 @@ class _Sandbox(_Object, type_prefix="sb"):
748
756
  stderr: StreamType = StreamType.PIPE,
749
757
  timeout: Optional[int] = None,
750
758
  workdir: Optional[str] = None,
751
- secrets: Sequence[_Secret] = (),
759
+ env: Optional[dict[str, Optional[str]]] = None, # Environment variables to set during command execution.
760
+ secrets: Optional[
761
+ Collection[_Secret]
762
+ ] = None, # Secrets to inject as environment variables during command execution.
752
763
  # Encode output as text.
753
764
  text: bool = True,
754
765
  # Control line-buffered output.
@@ -793,6 +804,7 @@ class _Sandbox(_Object, type_prefix="sb"):
793
804
  stderr=stderr,
794
805
  timeout=timeout,
795
806
  workdir=workdir,
807
+ env=env,
796
808
  secrets=secrets,
797
809
  text=text,
798
810
  bufsize=bufsize,
@@ -806,7 +818,8 @@ class _Sandbox(_Object, type_prefix="sb"):
806
818
  stderr: StreamType = StreamType.PIPE,
807
819
  timeout: Optional[int] = None,
808
820
  workdir: Optional[str] = None,
809
- secrets: Sequence[_Secret] = (),
821
+ env: Optional[dict[str, Optional[str]]] = None,
822
+ secrets: Optional[Collection[_Secret]] = None,
810
823
  text: bool = True,
811
824
  bufsize: Literal[-1, 1] = -1,
812
825
  ) -> Union[_ContainerProcess[bytes], _ContainerProcess[str]]:
@@ -818,6 +831,10 @@ class _Sandbox(_Object, type_prefix="sb"):
818
831
  raise InvalidError(f"workdir must be an absolute path, got: {workdir}")
819
832
  _validate_exec_args(args)
820
833
 
834
+ secrets = secrets or []
835
+ if env:
836
+ secrets = [*secrets, _Secret.from_dict(env)]
837
+
821
838
  # Force secret resolution so we can pass the secret IDs to the backend.
822
839
  secret_coros = [secret.hydrate(client=self._client) for secret in secrets]
823
840
  await TaskContext.gather(*secret_coros)
modal/sandbox.pyi CHANGED
@@ -90,7 +90,7 @@ class _Sandbox(modal._object._Object):
90
90
  def _new(
91
91
  args: collections.abc.Sequence[str],
92
92
  image: modal.image._Image,
93
- secrets: collections.abc.Sequence[modal.secret._Secret],
93
+ secrets: collections.abc.Collection[modal.secret._Secret],
94
94
  name: typing.Optional[str] = None,
95
95
  timeout: int = 300,
96
96
  idle_timeout: typing.Optional[int] = None,
@@ -128,7 +128,8 @@ class _Sandbox(modal._object._Object):
128
128
  app: typing.Optional[modal.app._App] = None,
129
129
  name: typing.Optional[str] = None,
130
130
  image: typing.Optional[modal.image._Image] = None,
131
- secrets: collections.abc.Sequence[modal.secret._Secret] = (),
131
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
132
+ secrets: typing.Optional[collections.abc.Collection[modal.secret._Secret]] = None,
132
133
  network_file_systems: dict[typing.Union[str, os.PathLike], modal.network_file_system._NetworkFileSystem] = {},
133
134
  timeout: int = 300,
134
135
  idle_timeout: typing.Optional[int] = None,
@@ -178,7 +179,8 @@ class _Sandbox(modal._object._Object):
178
179
  app: typing.Optional[modal.app._App] = None,
179
180
  name: typing.Optional[str] = None,
180
181
  image: typing.Optional[modal.image._Image] = None,
181
- secrets: collections.abc.Sequence[modal.secret._Secret] = (),
182
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
183
+ secrets: typing.Optional[collections.abc.Collection[modal.secret._Secret]] = None,
182
184
  mounts: collections.abc.Sequence[modal.mount._Mount] = (),
183
185
  network_file_systems: dict[typing.Union[str, os.PathLike], modal.network_file_system._NetworkFileSystem] = {},
184
186
  timeout: int = 300,
@@ -307,7 +309,8 @@ class _Sandbox(modal._object._Object):
307
309
  stderr: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
308
310
  timeout: typing.Optional[int] = None,
309
311
  workdir: typing.Optional[str] = None,
310
- secrets: collections.abc.Sequence[modal.secret._Secret] = (),
312
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
313
+ secrets: typing.Optional[collections.abc.Collection[modal.secret._Secret]] = None,
311
314
  text: typing.Literal[True] = True,
312
315
  bufsize: typing.Literal[-1, 1] = -1,
313
316
  pty: bool = False,
@@ -322,7 +325,8 @@ class _Sandbox(modal._object._Object):
322
325
  stderr: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
323
326
  timeout: typing.Optional[int] = None,
324
327
  workdir: typing.Optional[str] = None,
325
- secrets: collections.abc.Sequence[modal.secret._Secret] = (),
328
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
329
+ secrets: typing.Optional[collections.abc.Collection[modal.secret._Secret]] = None,
326
330
  text: typing.Literal[False] = False,
327
331
  bufsize: typing.Literal[-1, 1] = -1,
328
332
  pty: bool = False,
@@ -337,7 +341,8 @@ class _Sandbox(modal._object._Object):
337
341
  stderr: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
338
342
  timeout: typing.Optional[int] = None,
339
343
  workdir: typing.Optional[str] = None,
340
- secrets: collections.abc.Sequence[modal.secret._Secret] = (),
344
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
345
+ secrets: typing.Optional[collections.abc.Collection[modal.secret._Secret]] = None,
341
346
  text: bool = True,
342
347
  bufsize: typing.Literal[-1, 1] = -1,
343
348
  ) -> typing.Union[modal.container_process._ContainerProcess[bytes], modal.container_process._ContainerProcess[str]]:
@@ -446,7 +451,7 @@ class Sandbox(modal.object.Object):
446
451
  def _new(
447
452
  args: collections.abc.Sequence[str],
448
453
  image: modal.image.Image,
449
- secrets: collections.abc.Sequence[modal.secret.Secret],
454
+ secrets: collections.abc.Collection[modal.secret.Secret],
450
455
  name: typing.Optional[str] = None,
451
456
  timeout: int = 300,
452
457
  idle_timeout: typing.Optional[int] = None,
@@ -485,7 +490,8 @@ class Sandbox(modal.object.Object):
485
490
  app: typing.Optional[modal.app.App] = None,
486
491
  name: typing.Optional[str] = None,
487
492
  image: typing.Optional[modal.image.Image] = None,
488
- secrets: collections.abc.Sequence[modal.secret.Secret] = (),
493
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
494
+ secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
489
495
  network_file_systems: dict[
490
496
  typing.Union[str, os.PathLike], modal.network_file_system.NetworkFileSystem
491
497
  ] = {},
@@ -538,7 +544,8 @@ class Sandbox(modal.object.Object):
538
544
  app: typing.Optional[modal.app.App] = None,
539
545
  name: typing.Optional[str] = None,
540
546
  image: typing.Optional[modal.image.Image] = None,
541
- secrets: collections.abc.Sequence[modal.secret.Secret] = (),
547
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
548
+ secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
542
549
  network_file_systems: dict[
543
550
  typing.Union[str, os.PathLike], modal.network_file_system.NetworkFileSystem
544
551
  ] = {},
@@ -594,7 +601,8 @@ class Sandbox(modal.object.Object):
594
601
  app: typing.Optional[modal.app.App] = None,
595
602
  name: typing.Optional[str] = None,
596
603
  image: typing.Optional[modal.image.Image] = None,
597
- secrets: collections.abc.Sequence[modal.secret.Secret] = (),
604
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
605
+ secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
598
606
  mounts: collections.abc.Sequence[modal.mount.Mount] = (),
599
607
  network_file_systems: dict[
600
608
  typing.Union[str, os.PathLike], modal.network_file_system.NetworkFileSystem
@@ -640,7 +648,8 @@ class Sandbox(modal.object.Object):
640
648
  app: typing.Optional[modal.app.App] = None,
641
649
  name: typing.Optional[str] = None,
642
650
  image: typing.Optional[modal.image.Image] = None,
643
- secrets: collections.abc.Sequence[modal.secret.Secret] = (),
651
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
652
+ secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
644
653
  mounts: collections.abc.Sequence[modal.mount.Mount] = (),
645
654
  network_file_systems: dict[
646
655
  typing.Union[str, os.PathLike], modal.network_file_system.NetworkFileSystem
@@ -893,7 +902,8 @@ class Sandbox(modal.object.Object):
893
902
  stderr: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
894
903
  timeout: typing.Optional[int] = None,
895
904
  workdir: typing.Optional[str] = None,
896
- secrets: collections.abc.Sequence[modal.secret.Secret] = (),
905
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
906
+ secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
897
907
  text: typing.Literal[True] = True,
898
908
  bufsize: typing.Literal[-1, 1] = -1,
899
909
  pty: bool = False,
@@ -909,7 +919,8 @@ class Sandbox(modal.object.Object):
909
919
  stderr: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
910
920
  timeout: typing.Optional[int] = None,
911
921
  workdir: typing.Optional[str] = None,
912
- secrets: collections.abc.Sequence[modal.secret.Secret] = (),
922
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
923
+ secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
913
924
  text: typing.Literal[False] = False,
914
925
  bufsize: typing.Literal[-1, 1] = -1,
915
926
  pty: bool = False,
@@ -925,7 +936,8 @@ class Sandbox(modal.object.Object):
925
936
  stderr: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
926
937
  timeout: typing.Optional[int] = None,
927
938
  workdir: typing.Optional[str] = None,
928
- secrets: collections.abc.Sequence[modal.secret.Secret] = (),
939
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
940
+ secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
929
941
  text: typing.Literal[True] = True,
930
942
  bufsize: typing.Literal[-1, 1] = -1,
931
943
  pty: bool = False,
@@ -941,7 +953,8 @@ class Sandbox(modal.object.Object):
941
953
  stderr: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
942
954
  timeout: typing.Optional[int] = None,
943
955
  workdir: typing.Optional[str] = None,
944
- secrets: collections.abc.Sequence[modal.secret.Secret] = (),
956
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
957
+ secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
945
958
  text: typing.Literal[False] = False,
946
959
  bufsize: typing.Literal[-1, 1] = -1,
947
960
  pty: bool = False,
@@ -961,7 +974,8 @@ class Sandbox(modal.object.Object):
961
974
  stderr: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
962
975
  timeout: typing.Optional[int] = None,
963
976
  workdir: typing.Optional[str] = None,
964
- secrets: collections.abc.Sequence[modal.secret.Secret] = (),
977
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
978
+ secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
965
979
  text: bool = True,
966
980
  bufsize: typing.Literal[-1, 1] = -1,
967
981
  ) -> typing.Union[
@@ -982,7 +996,8 @@ class Sandbox(modal.object.Object):
982
996
  stderr: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
983
997
  timeout: typing.Optional[int] = None,
984
998
  workdir: typing.Optional[str] = None,
985
- secrets: collections.abc.Sequence[modal.secret.Secret] = (),
999
+ env: typing.Optional[dict[str, typing.Optional[str]]] = None,
1000
+ secrets: typing.Optional[collections.abc.Collection[modal.secret.Secret]] = None,
986
1001
  text: bool = True,
987
1002
  bufsize: typing.Literal[-1, 1] = -1,
988
1003
  ) -> typing.Union[
modal/secret.py CHANGED
@@ -239,7 +239,7 @@ class _Secret(_Object, type_prefix="st"):
239
239
  @staticmethod
240
240
  def from_dict(
241
241
  env_dict: dict[
242
- str, Union[str, None]
242
+ str, Optional[str]
243
243
  ] = {}, # dict of entries to be inserted as environment variables in functions using the secret
244
244
  ) -> "_Secret":
245
245
  """Create a secret from a str-str dictionary. Values can also be `None`, which is ignored.
@@ -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
@@ -3,7 +3,7 @@ modal/__main__.py,sha256=45H-GtwzaDfN-1nP4_HYvzN3s7AG_HXR4-ynrsjO_OI,2803
3
3
  modal/_clustered_functions.py,sha256=Sy4Sf_17EO8OL-FUe8LYcm4hrqLyQFCssNhr3p0SroU,3013
4
4
  modal/_clustered_functions.pyi,sha256=JmYwAGOLEnD5AF-gYF9O5tu-SgGjeoJz-X1j48b1Ijg,1157
5
5
  modal/_container_entrypoint.py,sha256=a1HAQYh1gGpqHuhSw6AW7XDYHztbeYr5a8iNnfCnoks,29023
6
- modal/_functions.py,sha256=JL6oB_uSTL6T3JCFrespKlbWmHdCQ66sspbQ9Ys1w88,89527
6
+ modal/_functions.py,sha256=1ZG8TvI3TTByfzArrjSww6pQB1iH4be0I3yQfkMfgAY,89780
7
7
  modal/_ipython.py,sha256=TW1fkVOmZL3YYqdS2YlM1hqpf654Yf8ZyybHdBnlhSw,301
8
8
  modal/_location.py,sha256=joiX-0ZeutEUDTrrqLF1GHXCdVLF-rHzstocbMcd_-k,366
9
9
  modal/_object.py,sha256=gwsLdXb-Ecd8nH8LVCo8oVZPzzdyo9BrN1DjgQmsSuM,11967
@@ -18,15 +18,15 @@ modal/_tunnel.py,sha256=zTBxBiuH1O22tS1OliAJdIsSmaZS8PlnifS_6S5z-mk,6320
18
18
  modal/_tunnel.pyi,sha256=rvC7USR2BcKkbZIeCJXwf7-UfGE-LPLjKsGNiK7Lxa4,13366
19
19
  modal/_type_manager.py,sha256=DWjgmjYJuOagw2erin506UUbG2H5UzZCFEekS-7hmfA,9087
20
20
  modal/_watcher.py,sha256=K6LYnlmSGQB4tWWI9JADv-tvSvQ1j522FwT71B51CX8,3584
21
- modal/app.py,sha256=F4baVULljFq0CwC_7U-EKNRNx7CYeWBKudjjYUuWc4U,48416
22
- modal/app.pyi,sha256=AbXJCBkyt2rI_-M3VbTBYb32at0P6iRZuoC87xY_JrQ,43591
21
+ modal/app.py,sha256=OBFaL-8KVMtBMEmspHA76LvblPdnSgdoGioLkQBjhdQ,48851
22
+ modal/app.pyi,sha256=Cqk3pOeEEroCLejj3yJ3XHDqt0rMzeSA295gMKEx6Ww,43955
23
23
  modal/call_graph.py,sha256=1g2DGcMIJvRy-xKicuf63IVE98gJSnQsr8R_NVMptNc,2581
24
24
  modal/client.py,sha256=kyAIVB3Ay-XKJizQ_1ufUFB__EagV0MLmHJpyYyJ7J0,18636
25
- modal/client.pyi,sha256=C26WWTgMvVwreVQHp7K60BAvXsFHKNRBTuPckNk0GTk,15831
25
+ modal/client.pyi,sha256=i4IpZBZyoAz8wGfv8tH9R0UgtbLAMraQhjBCPHxbHOw,15831
26
26
  modal/cloud_bucket_mount.py,sha256=YOe9nnvSr4ZbeCn587d7_VhE9IioZYRvF9VYQTQux08,5914
27
27
  modal/cloud_bucket_mount.pyi,sha256=-qSfYAQvIoO_l2wsCCGTG5ZUwQieNKXdAO00yP1-LYU,7394
28
- modal/cls.py,sha256=pTEO7pHjlO7taMbIqs4oI9ZZgKDJpVKyGkO5ZT0w6tQ,40934
29
- modal/cls.pyi,sha256=C1eK-AkN-QaeXu0qmMZVgJmkb1tYAFS43iEG37takDs,28959
28
+ modal/cls.py,sha256=qb9h_ZKiz2q7fwKQ-5bdkz1x3tdu6sIm-UI09aQjPPc,41101
29
+ modal/cls.pyi,sha256=C_bOybNa5iaVCcea-o8M1ATqpAbsQTtS9jN3OiEqhNY,29171
30
30
  modal/config.py,sha256=hpcfT03tdB-G0exZ4HjYDHwDtA8XcnliiyZzCcTbr8o,12124
31
31
  modal/container_process.py,sha256=Mutkl7sg_WR5zP4oJiWSC-3UdYRqp0zdKi1shZbi-bk,6996
32
32
  modal/container_process.pyi,sha256=9m-st3hCUlNN1GOTctfPPvIvoLtEl7FbuGWwif5-7YU,6037
@@ -39,10 +39,10 @@ modal/file_io.py,sha256=OSKr77TujcXGJW1iikzYiHckLSmv07QBgBHcxxYEkoI,21456
39
39
  modal/file_io.pyi,sha256=xtO6Glf_BFwDE7QiQQo24QqcMf_Vv-iz7WojcGVlLBU,15932
40
40
  modal/file_pattern_matcher.py,sha256=A_Kdkej6q7YQyhM_2-BvpFmPqJ0oHb54B6yf9VqvPVE,8116
41
41
  modal/functions.py,sha256=kcNHvqeGBxPI7Cgd57NIBBghkfbeFJzXO44WW0jSmao,325
42
- modal/functions.pyi,sha256=cDqhpIM5caoCR18_8krpAmPOd4QvEbm1ypYUZ6Ze9Wo,39404
42
+ modal/functions.pyi,sha256=AKLl2WxKWcC3vDfhCJ2sbkj-JUMWnRkOcNywjy_wsHs,39558
43
43
  modal/gpu.py,sha256=Fe5ORvVPDIstSq1xjmM6OoNgLYFWvogP9r5BgmD3hYg,6769
44
- modal/image.py,sha256=nXN9k_6gApHFy8-Bk_XT2Zu3jsDsGVrC3QcuiDC4yRY,103543
45
- modal/image.pyi,sha256=vKdb5PpYM8wcpq9PQegeVMjrPLzAipuV4q994NZiL84,69325
44
+ modal/image.py,sha256=wlOJ4bQxFLx2PlIIAmqZnFxFeERbZJGLYYWO7wlIZso,105969
45
+ modal/image.pyi,sha256=iFC8W6bl3KH_w15pm7B_UqeeGJZ44X7v20Ue_FlxPxw,71695
46
46
  modal/io_streams.py,sha256=hZOVc5beOAm8S_VQQmmKUbk_BJ9OltN83RY0yMPqUDo,16545
47
47
  modal/io_streams.pyi,sha256=aOun_jUFKHSJyUY6-7gKvNoxzcULsa8_hxdtEO7v-gk,13980
48
48
  modal/mount.py,sha256=3WpYaaCBGLyawW2uhQzB4jXRBQEsuuRMxnCFsXSa9_k,37470
@@ -65,11 +65,11 @@ modal/retries.py,sha256=IvNLDM0f_GLUDD5VgEDoN09C88yoxSrCquinAuxT1Sc,5205
65
65
  modal/runner.py,sha256=Q9wGTeg6sYyusTgwXSinoIti4Gv5LsiadAvflgETBHc,24070
66
66
  modal/runner.pyi,sha256=lbwLljm1cC8d6PcNvmYQhkE8501V9fg0bYqqKX6G4r4,8489
67
67
  modal/running_app.py,sha256=v61mapYNV1-O-Uaho5EfJlryMLvIT9We0amUOSvSGx8,1188
68
- modal/sandbox.py,sha256=AUZSOr7pF6BMaR7DuoVlIz-RkKTbQakv_ZBVmLJ2YB4,44222
69
- modal/sandbox.pyi,sha256=Dk9eN2wvQQtctb7WYV8WkHnfto4tQzSFpuqa7dCnPfs,48600
68
+ modal/sandbox.py,sha256=0UxFF-yCfD7SiQbAWCZT6f7lNk7wCY6A4p8lvwfImgk,45162
69
+ modal/sandbox.pyi,sha256=pFVN-LZvRt3eMI_XFTJpPtBwxwoRc8CkytAYe4R_SU8,50009
70
70
  modal/schedule.py,sha256=ng0g0AqNY5GQI9KhkXZQ5Wam5G42glbkqVQsNpBtbDE,3078
71
71
  modal/scheduler_placement.py,sha256=BAREdOY5HzHpzSBqt6jDVR6YC_jYfHMVqOzkyqQfngU,1235
72
- modal/secret.py,sha256=jcNJKc4ZB2nvAn7HJFawInqE-_7sbB43IWLZwyLBQ28,19308
72
+ modal/secret.py,sha256=EifrHTx7QmU4DTU3QwedD7O4ma52hHL4Qku1dADjY0E,19305
73
73
  modal/secret.pyi,sha256=7EzD7nZGSZHQR-Hf5aRi0ooZGxvy1-G8A4ul-M04Qs4,21552
74
74
  modal/serving.py,sha256=3I3WBeVbzZY258u9PXBCW_dZBgypq3OhwBuTVvlgubE,4423
75
75
  modal/serving.pyi,sha256=YfixTaWikyYpwhnNxCHMZnDDQiPmV1xJ87QF91U_WGU,1924
@@ -153,7 +153,7 @@ modal/experimental/__init__.py,sha256=fCqzo_f3vcY750vHtd7CtLs5dvdM_C0ZLLGb3zXuK9
153
153
  modal/experimental/flash.py,sha256=8HOHZ0XLSN8Znzsi6hGggS46CC6t_7IgGWyNoeSXS9o,28417
154
154
  modal/experimental/flash.pyi,sha256=R9VV0UDotiY9BRUjacB-xI4qhR3yBymAvEZFRFHztLs,15143
155
155
  modal/experimental/ipython.py,sha256=TrCfmol9LGsRZMeDoeMPx3Hv3BFqQhYnmD_iH0pqdhk,2904
156
- modal-1.1.5.dev20.dist-info/licenses/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
156
+ modal-1.1.5.dev22.dist-info/licenses/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
157
157
  modal_docs/__init__.py,sha256=svYKtV8HDwDCN86zbdWqyq5T8sMdGDj0PVlzc2tIxDM,28
158
158
  modal_docs/gen_cli_docs.py,sha256=c1yfBS_x--gL5bs0N4ihMwqwX8l3IBWSkBAKNNIi6bQ,3801
159
159
  modal_docs/gen_reference_docs.py,sha256=d_CQUGQ0rfw28u75I2mov9AlS773z9rG40-yq5o7g2U,6359
@@ -176,10 +176,10 @@ modal_proto/options_pb2.pyi,sha256=l7DBrbLO7q3Ir-XDkWsajm0d0TQqqrfuX54i4BMpdQg,1
176
176
  modal_proto/options_pb2_grpc.py,sha256=1oboBPFxaTEXt9Aw7EAj8gXHDCNMhZD2VXqocC9l_gk,159
177
177
  modal_proto/options_pb2_grpc.pyi,sha256=CImmhxHsYnF09iENPoe8S4J-n93jtgUYD2JPAc0yJSI,247
178
178
  modal_proto/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
179
- modal_version/__init__.py,sha256=JoRPUHSTT5B0elviCXt3qLm4PYL1rVJHN1v6kQwjN2U,121
179
+ modal_version/__init__.py,sha256=5dalLLvwzLOzWWIsM-DirmmYqjUqmI2Whec8hCSnPvQ,121
180
180
  modal_version/__main__.py,sha256=2FO0yYQQwDTh6udt1h-cBnGd1c4ZyHnHSI4BksxzVac,105
181
- modal-1.1.5.dev20.dist-info/METADATA,sha256=b9tvnlJO11F6K419bbfP5gMlwgG-BfbMZdDHwrrPdBs,2460
182
- modal-1.1.5.dev20.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
183
- modal-1.1.5.dev20.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
184
- modal-1.1.5.dev20.dist-info/top_level.txt,sha256=4BWzoKYREKUZ5iyPzZpjqx4G8uB5TWxXPDwibLcVa7k,43
185
- modal-1.1.5.dev20.dist-info/RECORD,,
181
+ modal-1.1.5.dev22.dist-info/METADATA,sha256=cd7GvW743zbi3TV82_2mSVCrBEOZoh7x7jhQ5phMiQg,2460
182
+ modal-1.1.5.dev22.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
183
+ modal-1.1.5.dev22.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
184
+ modal-1.1.5.dev22.dist-info/top_level.txt,sha256=4BWzoKYREKUZ5iyPzZpjqx4G8uB5TWxXPDwibLcVa7k,43
185
+ modal-1.1.5.dev22.dist-info/RECORD,,
modal_version/__init__.py CHANGED
@@ -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.5.dev20"
4
+ __version__ = "1.1.5.dev22"