modal 1.0.4.dev7__py3-none-any.whl → 1.0.4.dev10__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.dev10",
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.dev10",
98
98
  ): ...
99
99
  def is_closed(self) -> bool: ...
100
100
  @property
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.dev10
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License: Apache-2.0
@@ -22,7 +22,7 @@ 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=rX7aILLKNY7gU3DXvvGNT9Hi5IheqO6l0iFjSfDZMCw,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
28
  modal/cls.py,sha256=dBbeARwOWftlKd1cwtM0cHFtQWSWkwVXwVmOV4w0SyI,37907
@@ -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.dev10.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
@@ -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=LNXQQhlCrbhgsIePbjkDp4B4zhO1mSW6NEDtVxtRmu4,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.dev10.dist-info/METADATA,sha256=4tXSMwgkVzvte0dFfa9VIzNOYw3u0L4DGTh5oDHfw8U,2455
176
+ modal-1.0.4.dev10.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
177
+ modal-1.0.4.dev10.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
178
+ modal-1.0.4.dev10.dist-info/top_level.txt,sha256=4BWzoKYREKUZ5iyPzZpjqx4G8uB5TWxXPDwibLcVa7k,43
179
+ modal-1.0.4.dev10.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.0.4.dev7"
4
+ __version__ = "1.0.4.dev10"