modal 1.0.4.dev7__py3-none-any.whl → 1.0.4.dev12__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.
@@ -203,8 +203,11 @@ async def rm(
203
203
  ):
204
204
  ensure_env(env)
205
205
  volume = _NetworkFileSystem.from_name(volume_name)
206
+ console = Console()
206
207
  try:
207
208
  await volume.remove_file(remote_path, recursive=recursive)
209
+ console.print(OutputManager.step_completed(f"{remote_path} was deleted successfully!"))
210
+
208
211
  except GRPCError as exc:
209
212
  if exc.status in (Status.NOT_FOUND, Status.INVALID_ARGUMENT):
210
213
  raise UsageError(exc.message)
modal/cli/run.py CHANGED
@@ -27,6 +27,7 @@ from ..functions import Function
27
27
  from ..image import Image
28
28
  from ..output import enable_output
29
29
  from ..runner import deploy_app, interactive_shell, run_app
30
+ from ..secret import Secret
30
31
  from ..serving import serve_app
31
32
  from ..volume import Volume
32
33
  from .import_refs import (
@@ -531,6 +532,10 @@ def shell(
531
532
  " Can be used multiple times."
532
533
  ),
533
534
  ),
535
+ secret: Optional[list[str]] = typer.Option(
536
+ default=None,
537
+ help=("Name of a `modal.Secret` to mount inside the shell (if not using REF). Can be used multiple times."),
538
+ ),
534
539
  cpu: Optional[int] = typer.Option(default=None, help="Number of CPUs to allocate to the shell (if not using REF)."),
535
540
  memory: Optional[int] = typer.Option(
536
541
  default=None, help="Memory to allocate for the shell, in MiB (if not using REF)."
@@ -660,6 +665,7 @@ def shell(
660
665
  else:
661
666
  modal_image = Image.from_registry(image, add_python=add_python) if image else None
662
667
  volumes = {} if volume is None else {f"/mnt/{vol}": Volume.from_name(vol) for vol in volume}
668
+ secrets = [] if secret is None else [Secret.from_name(s) for s in secret]
663
669
  start_shell = partial(
664
670
  interactive_shell,
665
671
  image=modal_image,
@@ -668,6 +674,7 @@ def shell(
668
674
  gpu=gpu,
669
675
  cloud=cloud,
670
676
  volumes=volumes,
677
+ secrets=secrets,
671
678
  region=region.split(",") if region else [],
672
679
  pty=pty,
673
680
  )
modal/cli/volume.py CHANGED
@@ -245,8 +245,10 @@ async def rm(
245
245
  ):
246
246
  ensure_env(env)
247
247
  volume = _Volume.from_name(volume_name, environment_name=env)
248
+ console = Console()
248
249
  try:
249
250
  await volume.remove_file(remote_path, recursive=recursive)
251
+ console.print(OutputManager.step_completed(f"{remote_path} was deleted successfully!"))
250
252
  except GRPCError as exc:
251
253
  if exc.status in (Status.NOT_FOUND, Status.INVALID_ARGUMENT):
252
254
  raise UsageError(exc.message)
modal/client.pyi CHANGED
@@ -31,7 +31,7 @@ class _Client:
31
31
  server_url: str,
32
32
  client_type: int,
33
33
  credentials: typing.Optional[tuple[str, str]],
34
- version: str = "1.0.4.dev7",
34
+ version: str = "1.0.4.dev12",
35
35
  ): ...
36
36
  def is_closed(self) -> bool: ...
37
37
  @property
@@ -94,7 +94,7 @@ class Client:
94
94
  server_url: str,
95
95
  client_type: int,
96
96
  credentials: typing.Optional[tuple[str, str]],
97
- version: str = "1.0.4.dev7",
97
+ version: str = "1.0.4.dev12",
98
98
  ): ...
99
99
  def is_closed(self) -> bool: ...
100
100
  @property
modal/cls.py CHANGED
@@ -75,6 +75,7 @@ def _get_class_constructor_signature(user_cls: type) -> inspect.Signature:
75
75
 
76
76
  @dataclasses.dataclass()
77
77
  class _ServiceOptions:
78
+ # Note that default values should always be "untruthy" so we can detect when they are not set
78
79
  secrets: typing.Collection[_Secret] = ()
79
80
  validated_volumes: typing.Sequence[tuple[str, _Volume]] = ()
80
81
  resources: Optional[api_pb2.Resources] = None
@@ -88,6 +89,25 @@ class _ServiceOptions:
88
89
  batch_max_size: Optional[int] = None
89
90
  batch_wait_ms: Optional[int] = None
90
91
 
92
+ def merge_options(self, new_options: "_ServiceOptions") -> "_ServiceOptions":
93
+ """Implement protobuf-like MergeFrom semantics for this dataclass.
94
+
95
+ This mostly exists to support "stacking" of `.with_options()` calls.
96
+ """
97
+ new_options_dict = dataclasses.asdict(new_options)
98
+
99
+ # Resources needs special merge handling because individual fields are parameters in the public API
100
+ merged_resources = api_pb2.Resources()
101
+ if self.resources:
102
+ merged_resources.MergeFrom(self.resources)
103
+ if new_resources := new_options_dict.pop("resources"):
104
+ merged_resources.MergeFrom(new_resources)
105
+ self.resources = merged_resources
106
+
107
+ for key, value in new_options_dict.items():
108
+ if value: # Only overwrite data when the value was set in the new options
109
+ setattr(self, key, value)
110
+
91
111
 
92
112
  def _bind_instance_method(cls: "_Cls", service_function: _Function, method_name: str):
93
113
  """Binds an "instance service function" to a specific method using metadata for that method
@@ -664,15 +684,32 @@ More information on class parameterization can be found here: https://modal.com/
664
684
  container_idle_timeout: Optional[int] = None, # Now called `scaledown_window`
665
685
  allow_concurrent_inputs: Optional[int] = None, # See `.with_concurrency`
666
686
  ) -> "_Cls":
667
- """Create an instance of the Cls with configuration options overridden with new values.
687
+ """Override the static Function configuration at runtime.
688
+
689
+ This method will return a new instance of the cls that will autoscale independently of the
690
+ original instance. Note that options cannot be "unset" with this method (i.e., if a GPU
691
+ is configured in the `@app.cls()` decorator, passing `gpu=None` here will not create a
692
+ CPU-only instance).
668
693
 
669
694
  **Usage:**
670
695
 
696
+ You can use this method after looking up the Cls from a deployed App or if you have a
697
+ direct reference to a Cls from another Function or local entrypoint on its App:
698
+
671
699
  ```python notest
672
700
  Model = modal.Cls.from_name("my_app", "Model")
673
701
  ModelUsingGPU = Model.with_options(gpu="A100")
674
- ModelUsingGPU().generate.remote(42) # will run with an A100 GPU
702
+ ModelUsingGPU().generate.remote(input_prompt) # Run with an A100 GPU
675
703
  ```
704
+
705
+ The method can be called multiple times to "stack" updates:
706
+
707
+ ```python notest
708
+ Model.with_options(gpu="A100").with_options(scaledown_window=300) # Use an A100 with slow scaledown
709
+ ```
710
+
711
+ Note that container arguments (i.e. `volumes` and `secrets`) passed in subsequent calls
712
+ will not be merged.
676
713
  """
677
714
  retry_policy = _parse_retries(retries, f"Class {self.__name__}" if self._user_cls else "")
678
715
  if gpu or cpu or memory:
@@ -705,21 +742,23 @@ More information on class parameterization can be found here: https://modal.com/
705
742
 
706
743
  cls = _Cls._from_loader(_load_from_base, rep=f"{self._name}.with_options(...)", is_another_app=True, deps=_deps)
707
744
  cls._initialize_from_other(self)
708
- cls._options = dataclasses.replace(
709
- cls._options,
745
+
746
+ new_options = _ServiceOptions(
710
747
  secrets=secrets,
748
+ validated_volumes=validate_volumes(volumes),
711
749
  resources=resources,
712
750
  retry_policy=retry_policy,
713
751
  max_containers=max_containers,
714
752
  buffer_containers=buffer_containers,
715
753
  scaledown_window=scaledown_window,
716
754
  timeout_secs=timeout,
717
- validated_volumes=validate_volumes(volumes),
718
755
  # Note: set both for backwards / forwards compatibility
719
756
  # But going forward `.with_concurrency` is the preferred method with distinct parameterization
720
757
  max_concurrent_inputs=allow_concurrent_inputs,
721
758
  target_concurrent_inputs=allow_concurrent_inputs,
722
759
  )
760
+
761
+ cls._options.merge_options(new_options)
723
762
  return cls
724
763
 
725
764
  def with_concurrency(self: "_Cls", *, max_inputs: int, target_inputs: Optional[int] = None) -> "_Cls":
@@ -746,9 +785,9 @@ More information on class parameterization can be found here: https://modal.com/
746
785
  _load_from_base, rep=f"{self._name}.with_concurrency(...)", is_another_app=True, deps=_deps
747
786
  )
748
787
  cls._initialize_from_other(self)
749
- cls._options = dataclasses.replace(
750
- cls._options, max_concurrent_inputs=max_inputs, target_concurrent_inputs=target_inputs
751
- )
788
+
789
+ concurrency_options = _ServiceOptions(max_concurrent_inputs=max_inputs, target_concurrent_inputs=target_inputs)
790
+ cls._options.merge_options(concurrency_options)
752
791
  return cls
753
792
 
754
793
  def with_batching(self: "_Cls", *, max_batch_size: int, wait_ms: int) -> "_Cls":
@@ -775,7 +814,9 @@ More information on class parameterization can be found here: https://modal.com/
775
814
  _load_from_base, rep=f"{self._name}.with_concurrency(...)", is_another_app=True, deps=_deps
776
815
  )
777
816
  cls._initialize_from_other(self)
778
- cls._options = dataclasses.replace(cls._options, batch_max_size=max_batch_size, batch_wait_ms=wait_ms)
817
+
818
+ batching_options = _ServiceOptions(batch_max_size=max_batch_size, batch_wait_ms=wait_ms)
819
+ cls._options.merge_options(batching_options)
779
820
  return cls
780
821
 
781
822
  @staticmethod
modal/cls.pyi CHANGED
@@ -37,6 +37,7 @@ class _ServiceOptions:
37
37
  batch_max_size: typing.Optional[int]
38
38
  batch_wait_ms: typing.Optional[int]
39
39
 
40
+ def merge_options(self, new_options: _ServiceOptions) -> _ServiceOptions: ...
40
41
  def __init__(
41
42
  self,
42
43
  secrets: typing.Collection[modal.secret._Secret] = (),
modal/file_io.py CHANGED
@@ -144,11 +144,12 @@ class _FileIO(Generic[T]):
144
144
  _task_id: str = ""
145
145
  _file_descriptor: str = ""
146
146
  _client: _Client
147
- _watch_output_buffer: list[Optional[bytes]] = []
147
+ _watch_output_buffer: list[Union[Optional[bytes],Exception]] = []
148
148
 
149
149
  def __init__(self, client: _Client, task_id: str) -> None:
150
150
  self._client = client
151
151
  self._task_id = task_id
152
+ self._watch_output_buffer = []
152
153
 
153
154
  def _validate_mode(self, mode: str) -> None:
154
155
  if not any(char in mode for char in "rwax"):
@@ -173,11 +174,7 @@ class _FileIO(Generic[T]):
173
174
  raise ValueError(f"Invalid file mode: {mode}")
174
175
  seen_chars.add(char)
175
176
 
176
- def _handle_error(self, error: api_pb2.SystemErrorMessage) -> None:
177
- error_class = ERROR_MAPPING.get(error.error_code, FilesystemExecutionError)
178
- raise error_class(error.error_message)
179
-
180
- async def _consume_output(self, exec_id: str) -> AsyncIterator[Optional[bytes]]:
177
+ async def _consume_output(self, exec_id: str) -> AsyncIterator[Union[Optional[bytes], Exception]]:
181
178
  req = api_pb2.ContainerFilesystemExecGetOutputRequest(
182
179
  exec_id=exec_id,
183
180
  timeout=55,
@@ -187,7 +184,8 @@ class _FileIO(Generic[T]):
187
184
  yield None
188
185
  break
189
186
  if batch.HasField("error"):
190
- self._handle_error(batch.error)
187
+ error_class = ERROR_MAPPING.get(batch.error.error_code, FilesystemExecutionError)
188
+ yield error_class(batch.error.error_message)
191
189
  for message in batch.output:
192
190
  yield message
193
191
 
@@ -236,6 +234,8 @@ class _FileIO(Generic[T]):
236
234
  if data is None:
237
235
  completed = True
238
236
  break
237
+ if isinstance(data, Exception):
238
+ raise data
239
239
  output += data
240
240
  except (GRPCError, StreamTerminatedError) as exc:
241
241
  if retries_remaining > 0:
@@ -475,6 +475,8 @@ class _FileIO(Generic[T]):
475
475
  item = self._watch_output_buffer.pop(0)
476
476
  if item is None:
477
477
  break
478
+ if isinstance(item, Exception):
479
+ raise item
478
480
  buffer += item
479
481
  # a single event may be split across multiple messages
480
482
  # the end of an event is marked by two newlines
modal/file_io.pyi CHANGED
@@ -1,7 +1,6 @@
1
1
  import _typeshed
2
2
  import enum
3
3
  import modal.client
4
- import modal_proto.api_pb2
5
4
  import typing
6
5
  import typing_extensions
7
6
 
@@ -33,12 +32,11 @@ class _FileIO(typing.Generic[T]):
33
32
  _task_id: str
34
33
  _file_descriptor: str
35
34
  _client: modal.client._Client
36
- _watch_output_buffer: list[typing.Optional[bytes]]
35
+ _watch_output_buffer: list[typing.Union[bytes, None, Exception]]
37
36
 
38
37
  def __init__(self, client: modal.client._Client, task_id: str) -> None: ...
39
38
  def _validate_mode(self, mode: str) -> None: ...
40
- def _handle_error(self, error: modal_proto.api_pb2.SystemErrorMessage) -> None: ...
41
- def _consume_output(self, exec_id: str) -> typing.AsyncIterator[typing.Optional[bytes]]: ...
39
+ def _consume_output(self, exec_id: str) -> typing.AsyncIterator[typing.Union[bytes, None, Exception]]: ...
42
40
  async def _consume_watch_output(self, exec_id: str) -> None: ...
43
41
  async def _parse_watch_output(self, event: bytes) -> typing.Optional[FileWatchEvent]: ...
44
42
  async def _wait(self, exec_id: str) -> bytes: ...
@@ -112,15 +110,14 @@ class FileIO(typing.Generic[T]):
112
110
  _task_id: str
113
111
  _file_descriptor: str
114
112
  _client: modal.client.Client
115
- _watch_output_buffer: list[typing.Optional[bytes]]
113
+ _watch_output_buffer: list[typing.Union[bytes, None, Exception]]
116
114
 
117
115
  def __init__(self, client: modal.client.Client, task_id: str) -> None: ...
118
116
  def _validate_mode(self, mode: str) -> None: ...
119
- def _handle_error(self, error: modal_proto.api_pb2.SystemErrorMessage) -> None: ...
120
117
 
121
118
  class ___consume_output_spec(typing_extensions.Protocol[SUPERSELF]):
122
- def __call__(self, /, exec_id: str) -> typing.Iterator[typing.Optional[bytes]]: ...
123
- def aio(self, /, exec_id: str) -> typing.AsyncIterator[typing.Optional[bytes]]: ...
119
+ def __call__(self, /, exec_id: str) -> typing.Iterator[typing.Union[bytes, None, Exception]]: ...
120
+ def aio(self, /, exec_id: str) -> typing.AsyncIterator[typing.Union[bytes, None, Exception]]: ...
124
121
 
125
122
  _consume_output: ___consume_output_spec[typing_extensions.Self]
126
123
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.0.4.dev7
3
+ Version: 1.0.4.dev12
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License: Apache-2.0
@@ -22,11 +22,11 @@ modal/app.py,sha256=NZ_rJ9TuMfiNiLg8-gOFgufD5flGtXWPHOZI0gdD3hE,46585
22
22
  modal/app.pyi,sha256=4-b_vbe3lNAqQPcMRpQCEDsE1zsVkQRJGUql9B7HvbM,22659
23
23
  modal/call_graph.py,sha256=1g2DGcMIJvRy-xKicuf63IVE98gJSnQsr8R_NVMptNc,2581
24
24
  modal/client.py,sha256=OwISJvkgMb-rHm9Gc4i-7YcDgGiZgwJ7F_PzwZH7a6Q,16847
25
- modal/client.pyi,sha256=SmKlz-Y4g7AixfnoxqBH1SEeG53O1REtj_OWaOJNY_4,8457
25
+ modal/client.pyi,sha256=KVuhPigNi5GmL70lURFg0-4rTmfp21DMJVai9gIsgCs,8459
26
26
  modal/cloud_bucket_mount.py,sha256=YOe9nnvSr4ZbeCn587d7_VhE9IioZYRvF9VYQTQux08,5914
27
27
  modal/cloud_bucket_mount.pyi,sha256=30T3K1a89l6wzmEJ_J9iWv9SknoGqaZDx59Xs-ZQcmk,1607
28
- modal/cls.py,sha256=dBbeARwOWftlKd1cwtM0cHFtQWSWkwVXwVmOV4w0SyI,37907
29
- modal/cls.pyi,sha256=-gSV02T5S1La1dvmHHB_f139nNySk5MeXRSF4yp8z4s,12660
28
+ modal/cls.py,sha256=JjxAeVudXKMp-co9YUnsGG6COJOv91K0ylf4f3mR67o,39792
29
+ modal/cls.pyi,sha256=EL1mQuyf8nAL2AjVZVnZhDzhakUmQt1ZtOVMy_aYWJI,12742
30
30
  modal/config.py,sha256=e8sQ4RgwgJ_45S302vWUWs_wqRlKyEt3tU898RiaDKE,12073
31
31
  modal/container_process.py,sha256=PDvjcyZ6eeN8foKQgR0WJ66Sg3lt7OFhK7Y_Akz6k5w,5846
32
32
  modal/container_process.pyi,sha256=pPIUxVV_TY4huO2jF5cSSjb6L_EN7Es4xRvuwZ5sa5M,2802
@@ -35,8 +35,8 @@ modal/dict.pyi,sha256=RBaQyOd1ABRNN7vIf5L_rv94y7Kq5Qn9IlKHSr4j8N0,8120
35
35
  modal/environments.py,sha256=gHFNLG78bqgizpQ4w_elz27QOqmcgAonFsmLs7NjUJ4,6804
36
36
  modal/environments.pyi,sha256=4HbI0kywveaUVI7HqDtZ4HphCTGXYi_wie2hz87up5A,3425
37
37
  modal/exception.py,sha256=2pgq-j8JP-tB3yU2VmYOzn9CsynU9_h8IU_MgqgKegM,5352
38
- modal/file_io.py,sha256=lcMs_E9Xfm0YX1t9U2wNIBPnqHRxmImqjLW1GHqVmyg,20945
39
- modal/file_io.pyi,sha256=oB7x-rKq7bmm8cA7Z7W9C9yeko7KK9m9i5GidFnkGK4,9569
38
+ modal/file_io.py,sha256=SCBfLk5gRieqdTVlA_f-2YHHtRp7Iy_sA6iR1zPsO3c,21100
39
+ modal/file_io.pyi,sha256=IPQsnr5nn5Ci4OdjmRPSI1qi3AYamxWMhpEFNYPKlHM,9436
40
40
  modal/file_pattern_matcher.py,sha256=wov-otB5M1oTdrYDtR2_VgacYin2srdtAP4McA1Cqzw,6516
41
41
  modal/functions.py,sha256=kcNHvqeGBxPI7Cgd57NIBBghkfbeFJzXO44WW0jSmao,325
42
42
  modal/functions.pyi,sha256=iqdp5ixtOOlm8bF-QYbD_G8VKqSRt_AVLT7AWjpn6pQ,16236
@@ -127,14 +127,14 @@ modal/cli/entry_point.py,sha256=Ytpsy0MTLQC1RSClI0wNhCbiy6ecPO8555PMmsrxoSc,4377
127
127
  modal/cli/environment.py,sha256=Ayddkiq9jdj3XYDJ8ZmUqFpPPH8xajYlbexRkzGtUcg,4334
128
128
  modal/cli/import_refs.py,sha256=pmzY0hpexx6DtvobNmCOvRqEdS9IriEP4BpMw1TIy2w,13911
129
129
  modal/cli/launch.py,sha256=0_sBu6bv2xJEPWi-rbGS6Ri9ggnkWQvrGlgpYSUBMyY,3097
130
- modal/cli/network_file_system.py,sha256=DoIdY8I42DjFdTtaYuRKNm7GC6vY0QtA4mk6694fbuU,7983
130
+ modal/cli/network_file_system.py,sha256=1_BF95WPLHh7x37lr0JBx5nS8NsKXCDZKt0L2F5fHgo,8104
131
131
  modal/cli/profile.py,sha256=0TYhgRSGUvQZ5LH9nkl6iZllEvAjDniES264dE57wOM,3201
132
132
  modal/cli/queues.py,sha256=1OzC9HdCkbNz6twF3US4FZmIhuVRQ01GOfBY42ux61A,4533
133
- modal/cli/run.py,sha256=vB4Qc0w9-8778Kme038DPxpFLLVAGo_KcJ7403ikMJY,24325
133
+ modal/cli/run.py,sha256=T-Votd_0t3avdfB0HJ7cvQO6TyLHvzGJhk93FFopAbU,24658
134
134
  modal/cli/secret.py,sha256=2bngl3Gb6THXkQ2eWZIN9pOHeOFJqiSNo_waUCVYgns,6611
135
135
  modal/cli/token.py,sha256=mxSgOWakXG6N71hQb1ko61XAR9ZGkTMZD-Txn7gmTac,1924
136
136
  modal/cli/utils.py,sha256=9Q7DIUX78-c19zBQNA7EtkgqIFatvHWUVGHwUIeBX_0,3366
137
- modal/cli/volume.py,sha256=W7i4zJyHSPmvP4e4CEv739KpoDCmFO3aIXxPQuuetXg,10840
137
+ modal/cli/volume.py,sha256=KJ4WKQYjRGsTERkwHE1HcRia9rWzLIDDnlc89QmTLvE,10960
138
138
  modal/cli/programs/__init__.py,sha256=svYKtV8HDwDCN86zbdWqyq5T8sMdGDj0PVlzc2tIxDM,28
139
139
  modal/cli/programs/run_jupyter.py,sha256=44Lpvqk2l3hH-uOkmAOzw60NEsfB5uaRDWDKVshvQhs,2682
140
140
  modal/cli/programs/vscode.py,sha256=KbTAaIXyQBVCDXxXjmBHmKpgXkUw0q4R4KkJvUjCYgk,3380
@@ -147,7 +147,7 @@ modal/requirements/2024.10.txt,sha256=qD-5cVIVM9wXesJ6JC89Ew-3m2KjEElUz3jaw_MddR
147
147
  modal/requirements/PREVIEW.txt,sha256=KxDaVTOwatHvboDo4lorlgJ7-n-MfAwbPwxJ0zcJqrs,312
148
148
  modal/requirements/README.md,sha256=9tK76KP0Uph7O0M5oUgsSwEZDj5y-dcUPsnpR0Sc-Ik,854
149
149
  modal/requirements/base-images.json,sha256=f1bwyp2UkM844eoO9Qk30gQw_xrMqKpMSeJ6MErXnEk,995
150
- modal-1.0.4.dev7.dist-info/licenses/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
150
+ modal-1.0.4.dev12.dist-info/licenses/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
151
151
  modal_docs/__init__.py,sha256=svYKtV8HDwDCN86zbdWqyq5T8sMdGDj0PVlzc2tIxDM,28
152
152
  modal_docs/gen_cli_docs.py,sha256=c1yfBS_x--gL5bs0N4ihMwqwX8l3IBWSkBAKNNIi6bQ,3801
153
153
  modal_docs/gen_reference_docs.py,sha256=d_CQUGQ0rfw28u75I2mov9AlS773z9rG40-yq5o7g2U,6359
@@ -155,10 +155,10 @@ modal_docs/mdmd/__init__.py,sha256=svYKtV8HDwDCN86zbdWqyq5T8sMdGDj0PVlzc2tIxDM,2
155
155
  modal_docs/mdmd/mdmd.py,sha256=Irx49MCCTlBOP4FBdLR--JrpA3-WhsVeriq0LGgsRic,6232
156
156
  modal_docs/mdmd/signatures.py,sha256=XJaZrK7Mdepk5fdX51A8uENiLFNil85Ud0d4MH8H5f0,3218
157
157
  modal_proto/__init__.py,sha256=MIEP8jhXUeGq_eCjYFcqN5b1bxBM4fdk0VESpjWR0fc,28
158
- modal_proto/api.proto,sha256=nwh8RmhypmnFMKQ-WwHolz-1NvKr4JgRSc2As_cZ0JE,96407
158
+ modal_proto/api.proto,sha256=aBHQSEFm1Os9ciCl6N9N5bhumjdJIpl7VPSbP2Chjk4,96432
159
159
  modal_proto/api_grpc.py,sha256=iY5o_Tm4VDP-Wa1JgA_NpQa_Y-4FYB_RN9wdSUExjwI,117469
160
- modal_proto/api_pb2.py,sha256=UeQg7ABeXbNCBLcft3pTZtV6EoLMifZ_O_BPxYadm0w,338603
161
- modal_proto/api_pb2.pyi,sha256=QQp5_zlv3j6_v7CaqM4yFKW4xun1yzy4lxwkn4_O3Ew,463819
160
+ modal_proto/api_pb2.py,sha256=PTGsaddASU8iqRoaTFmV5bNg-TtGGUGvf8tTVWjeR1Q,338641
161
+ modal_proto/api_pb2.pyi,sha256=hMvUMcYnpt7tR0fdkL-sDuOM-r2vistuds_rL03xY-k,463959
162
162
  modal_proto/api_pb2_grpc.py,sha256=NL5prOS_hh_pA1hVvQP_ZRE1w49N-PR8iNPRZ65i6nA,254089
163
163
  modal_proto/api_pb2_grpc.pyi,sha256=Xxgdcnv1mBnu5_AQxJ6fo0yz7GnqVU0HVObNfZWHVfM,59440
164
164
  modal_proto/modal_api_grpc.py,sha256=0ir2lnwT3-IgPcAWw98yWMAiqZPkjvNro9UBk4u8hnk,17763
@@ -170,10 +170,10 @@ modal_proto/options_pb2.pyi,sha256=l7DBrbLO7q3Ir-XDkWsajm0d0TQqqrfuX54i4BMpdQg,1
170
170
  modal_proto/options_pb2_grpc.py,sha256=1oboBPFxaTEXt9Aw7EAj8gXHDCNMhZD2VXqocC9l_gk,159
171
171
  modal_proto/options_pb2_grpc.pyi,sha256=CImmhxHsYnF09iENPoe8S4J-n93jtgUYD2JPAc0yJSI,247
172
172
  modal_proto/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
173
- modal_version/__init__.py,sha256=KQX7NLXaoRwlQ1k2pQTMoFZbfScXzSl0HXpqxrX3LeQ,120
173
+ modal_version/__init__.py,sha256=EQ_zUTh_-WBVmHGSI7Yvy46jXn5PYMLFT67epWx6oLI,121
174
174
  modal_version/__main__.py,sha256=2FO0yYQQwDTh6udt1h-cBnGd1c4ZyHnHSI4BksxzVac,105
175
- modal-1.0.4.dev7.dist-info/METADATA,sha256=aviIfq7DJDr5f3Tt3PdLV4RzP7-SE2yKO3NmWIQ42xY,2454
176
- modal-1.0.4.dev7.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
177
- modal-1.0.4.dev7.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
178
- modal-1.0.4.dev7.dist-info/top_level.txt,sha256=4BWzoKYREKUZ5iyPzZpjqx4G8uB5TWxXPDwibLcVa7k,43
179
- modal-1.0.4.dev7.dist-info/RECORD,,
175
+ modal-1.0.4.dev12.dist-info/METADATA,sha256=mrPfy1u126T4G9QF_ieUE8KzjFPDiFZmJR1irfrXoJc,2455
176
+ modal-1.0.4.dev12.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
177
+ modal-1.0.4.dev12.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
178
+ modal-1.0.4.dev12.dist-info/top_level.txt,sha256=4BWzoKYREKUZ5iyPzZpjqx4G8uB5TWxXPDwibLcVa7k,43
179
+ modal-1.0.4.dev12.dist-info/RECORD,,
modal_proto/api.proto CHANGED
@@ -2796,6 +2796,7 @@ message TaskInfo {
2796
2796
  modal.client.GenericResult result = 4;
2797
2797
  double enqueued_at = 5;
2798
2798
  string gpu_type = 6;
2799
+ string sandbox_id = 7;
2799
2800
  }
2800
2801
 
2801
2802
  message TaskListRequest {