modal 1.5.2.dev3__py3-none-any.whl → 1.5.2.dev5__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.
@@ -264,7 +264,7 @@ class IOContext:
264
264
  if not inspect.isasyncgen(expected_async_gen):
265
265
  raise InvalidError(f"Async generator function returned value of type {type(expected_async_gen)}")
266
266
 
267
- async with aclosing(expected_async_gen) as gen:
267
+ async with aclosing(cast(AsyncGenerator[Any, None], expected_async_gen)) as gen:
268
268
  async for result in gen:
269
269
  yield result
270
270
  logger.debug(f"Finished generator input {self.input_ids}")
@@ -138,6 +138,13 @@ async def _upload_to_s3_url(
138
138
  text = await resp.text()
139
139
  except Exception:
140
140
  text = "<no body>"
141
+
142
+ if "The Content-MD5 you specified did not match what we received." in text:
143
+ raise ExecutionError(
144
+ "Hash mismatch during upload. This may be caused by files changing while an upload is in "
145
+ "progress. Please try again."
146
+ )
147
+
141
148
  raise ExecutionError(f"Put to url {upload_url} failed with status {resp.status}: {text}")
142
149
 
143
150
  # client side ETag checksum verification
modal/client.pyi CHANGED
@@ -35,7 +35,7 @@ class _Client:
35
35
  server_url: str,
36
36
  client_type: int,
37
37
  credentials: typing.Optional[tuple[str, str]],
38
- version: str = "1.5.2.dev3",
38
+ version: str = "1.5.2.dev5",
39
39
  ):
40
40
  """mdmd:hidden
41
41
  The Modal client object is not intended to be instantiated directly by users.
@@ -205,7 +205,7 @@ class Client:
205
205
  server_url: str,
206
206
  client_type: int,
207
207
  credentials: typing.Optional[tuple[str, str]],
208
- version: str = "1.5.2.dev3",
208
+ version: str = "1.5.2.dev5",
209
209
  ):
210
210
  """mdmd:hidden
211
211
  The Modal client object is not intended to be instantiated directly by users.
modal/functions.pyi CHANGED
@@ -490,7 +490,7 @@ class Function(
490
490
 
491
491
  _call_generator: ___call_generator_spec
492
492
 
493
- class __remote_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER]):
493
+ class __remote_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER]):
494
494
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> ReturnType_INNER:
495
495
  """Calls the function remotely, executing it with the given arguments and returning the execution's result.
496
496
 
@@ -515,7 +515,7 @@ class Function(
515
515
  """
516
516
  ...
517
517
 
518
- remote: __remote_spec[modal._functions.ReturnType, modal._functions.P]
518
+ remote: __remote_spec[modal._functions.P, modal._functions.ReturnType]
519
519
 
520
520
  class __remote_gen_spec(typing_extensions.Protocol):
521
521
  def __call__(self, /, *args, **kwargs) -> typing.Generator[typing.Any, None, None]:
@@ -565,7 +565,7 @@ class Function(
565
565
  """
566
566
  ...
567
567
 
568
- class ___experimental_spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER]):
568
+ class ___experimental_spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER]):
569
569
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
570
570
  """[Experimental] Calls the function with the given arguments, without waiting for the results.
571
571
 
@@ -598,7 +598,7 @@ class Function(
598
598
  """
599
599
  ...
600
600
 
601
- _experimental_spawn: ___experimental_spawn_spec[modal._functions.ReturnType, modal._functions.P]
601
+ _experimental_spawn: ___experimental_spawn_spec[modal._functions.P, modal._functions.ReturnType]
602
602
 
603
603
  class ___spawn_map_inner_spec(typing_extensions.Protocol[P_INNER]):
604
604
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> None: ...
@@ -606,7 +606,7 @@ class Function(
606
606
 
607
607
  _spawn_map_inner: ___spawn_map_inner_spec[modal._functions.P]
608
608
 
609
- class __spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER]):
609
+ class __spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER]):
610
610
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
611
611
  """Calls the function with the given arguments, without waiting for the results.
612
612
 
@@ -639,7 +639,7 @@ class Function(
639
639
  """
640
640
  ...
641
641
 
642
- spawn: __spawn_spec[modal._functions.ReturnType, modal._functions.P]
642
+ spawn: __spawn_spec[modal._functions.P, modal._functions.ReturnType]
643
643
 
644
644
  def get_raw_f(self) -> collections.abc.Callable[..., typing.Any]:
645
645
  """Return the inner Python object wrapped by this Modal Function.
modal/sandbox.py CHANGED
@@ -2056,7 +2056,6 @@ class _Sandbox(_Object, type_prefix="sb"):
2056
2056
  Returns:
2057
2057
  A `SandboxFilesystem` helper bound to this sandbox.
2058
2058
  """
2059
- self._ensure_v1("filesystem")
2060
2059
  self._ensure_attached()
2061
2060
  if self._filesystem is None:
2062
2061
  self._filesystem = _SandboxFilesystem(self)
@@ -2283,6 +2282,62 @@ class _Sandbox(_Object, type_prefix="sb"):
2283
2282
  # Fetch the next batch starting from the end of the current one.
2284
2283
  before_timestamp = resp.sandboxes[-1].created_at
2285
2284
 
2285
+ @staticmethod
2286
+ async def _experimental_list(
2287
+ *, app_id: str | None = None, client: _Client | None = None
2288
+ ) -> AsyncGenerator["_Sandbox", None]:
2289
+ """List v2 Sandboxes in an App.
2290
+
2291
+ This function lists v2 sandboxes, ie sandboxes created via modal.Sandbox._experimental_create.
2292
+ Filtering based on tags is not yet supported.
2293
+
2294
+ Args:
2295
+ app_id: The App to list Sandboxes under.
2296
+ client: Optional client to use for the session.
2297
+
2298
+ Yields:
2299
+ `Sandbox` objects that are currently running in the App.
2300
+ """
2301
+ if not app_id:
2302
+ raise InvalidError(
2303
+ "Sandbox._experimental_list requires an `app_id`:\n\n"
2304
+ 'app = modal.App.lookup("my-app")\n'
2305
+ "Sandbox._experimental_list(app_id=app.app_id)"
2306
+ )
2307
+
2308
+ before_timestamp = None
2309
+ if client is None:
2310
+ client = await _Client.from_env()
2311
+
2312
+ assert client._auth_token_manager
2313
+ while True:
2314
+ req = api_pb2.SandboxListRequest(
2315
+ app_id=app_id,
2316
+ before_timestamp=before_timestamp,
2317
+ include_finished=False,
2318
+ )
2319
+
2320
+ # Fetches a batch of sandboxes. SandboxListV2 authenticates via the
2321
+ # auth-token metadata, like the other V2 sandbox RPCs.
2322
+ auth_token = await client._auth_token_manager.get_token()
2323
+ resp = await client.stub.SandboxListV2(req, metadata=[("x-modal-auth-token", auth_token)])
2324
+
2325
+ if not resp.sandboxes:
2326
+ return
2327
+
2328
+ for sandbox_info in resp.sandboxes:
2329
+ sandbox_info: api_pb2.SandboxInfo
2330
+ obj = _Sandbox._new_hydrated(sandbox_info.id, client, None)
2331
+ # SandboxListV2 only returns V2 sandboxes; mark them as such so
2332
+ # operations like wait/terminate/exec use the V2 RPCs and stdio.
2333
+ obj._is_v2 = True
2334
+ obj._hydrate_metadata_v2()
2335
+ obj._result = sandbox_info.task_info.result
2336
+ yield obj
2337
+
2338
+ # Fetch the next batch starting from the end of the current one.
2339
+ before_timestamp = resp.sandboxes[-1].created_at
2340
+
2286
2341
 
2287
2342
  class _SidecarContainer:
2288
2343
  """Handle to an additional container running in a Sandbox."""
modal/sandbox.pyi CHANGED
@@ -942,6 +942,24 @@ class _Sandbox(modal._object._Object):
942
942
  """
943
943
  ...
944
944
 
945
+ @staticmethod
946
+ def _experimental_list(
947
+ *, app_id: typing.Optional[str] = None, client: typing.Optional[modal.client._Client] = None
948
+ ) -> collections.abc.AsyncGenerator[_Sandbox, None]:
949
+ """List v2 Sandboxes in an App.
950
+
951
+ This function lists v2 sandboxes, ie sandboxes created via modal.Sandbox._experimental_create.
952
+ Filtering based on tags is not yet supported.
953
+
954
+ Args:
955
+ app_id: The App to list Sandboxes under.
956
+ client: Optional client to use for the session.
957
+
958
+ Yields:
959
+ `Sandbox` objects that are currently running in the App.
960
+ """
961
+ ...
962
+
945
963
  class _SidecarContainer:
946
964
  """Handle to an additional container running in a Sandbox."""
947
965
 
@@ -2790,6 +2808,43 @@ class Sandbox(modal.object.Object):
2790
2808
 
2791
2809
  list: typing.ClassVar[__list_spec]
2792
2810
 
2811
+ class ___experimental_list_spec(typing_extensions.Protocol):
2812
+ def __call__(
2813
+ self, /, *, app_id: typing.Optional[str] = None, client: typing.Optional[modal.client.Client] = None
2814
+ ) -> typing.Generator[Sandbox, None, None]:
2815
+ """List v2 Sandboxes in an App.
2816
+
2817
+ This function lists v2 sandboxes, ie sandboxes created via modal.Sandbox._experimental_create.
2818
+ Filtering based on tags is not yet supported.
2819
+
2820
+ Args:
2821
+ app_id: The App to list Sandboxes under.
2822
+ client: Optional client to use for the session.
2823
+
2824
+ Yields:
2825
+ `Sandbox` objects that are currently running in the App.
2826
+ """
2827
+ ...
2828
+
2829
+ def aio(
2830
+ self, /, *, app_id: typing.Optional[str] = None, client: typing.Optional[modal.client.Client] = None
2831
+ ) -> collections.abc.AsyncGenerator[Sandbox, None]:
2832
+ """List v2 Sandboxes in an App.
2833
+
2834
+ This function lists v2 sandboxes, ie sandboxes created via modal.Sandbox._experimental_create.
2835
+ Filtering based on tags is not yet supported.
2836
+
2837
+ Args:
2838
+ app_id: The App to list Sandboxes under.
2839
+ client: Optional client to use for the session.
2840
+
2841
+ Yields:
2842
+ `Sandbox` objects that are currently running in the App.
2843
+ """
2844
+ ...
2845
+
2846
+ _experimental_list: typing.ClassVar[___experimental_list_spec]
2847
+
2793
2848
  _default_image: modal._image._Image
2794
2849
 
2795
2850
  _MAIN_CONTAINER_NAME: str
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.5.2.dev3
3
+ Version: 1.5.2.dev5
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License-Expression: Apache-2.0
@@ -31,7 +31,7 @@ modal/billing.py,sha256=tWrlpbNau0cfGSr643MzguHS0Dl5cRd7tm0GsCLYvtQ,372
31
31
  modal/billing.pyi,sha256=2hUdEbWa1nLdFfzZpwxHHpyK9k8uBRASGkFmPJhtkUU,7318
32
32
  modal/call_graph.py,sha256=k_wH3DuuUHCeuycHsOqlcOpIlIVbCYi9RPobg21hJdI,2550
33
33
  modal/client.py,sha256=OgjptM5UuU5LL85_-DFia-ehS8UCgMzVuzfNcxA1qPA,16136
34
- modal/client.pyi,sha256=-EPEnAI129D7HbPdJvWlfTwjx28EKu92b8PcKjsWhQU,17852
34
+ modal/client.pyi,sha256=nkN4HbEW0stuQNoVjY7wnPnD2e92Enn6D19zZj15gYU,17852
35
35
  modal/cloud_bucket_mount.py,sha256=03gECcV9l2Lnt9k23YrDOTGFW7ajfXMW5O8b1prhtwQ,6254
36
36
  modal/cloud_bucket_mount.pyi,sha256=lMOb44pbNE9kDVEqWfcmvpsnh1sdNNFzuKoVyZZ3d5M,8058
37
37
  modal/cls.py,sha256=4oWIthR84usP5oejQbdMWzXkvzXyER2GDIpLvLTH4Og,40936
@@ -48,7 +48,7 @@ modal/file_io.py,sha256=kfojtm0euzOMhfkVTAGyfuygDJ1XPPHQa5uUhkCsThg,21800
48
48
  modal/file_io.pyi,sha256=Tr0OtfbkTNa8v1dkGtl8l3RH58pMc9uGTYKxL1jNwho,15422
49
49
  modal/file_pattern_matcher.py,sha256=6g_awxudMy_ontBvkznybyeNnwGMj297YrmIHCbREI0,8132
50
50
  modal/functions.py,sha256=EZRcHFfnoYbvawUJnAHF5nIvoo9GX2Djy7mUmOCXmXc,258
51
- modal/functions.pyi,sha256=4G6CRSPa4c84nZNiiC0eoieyQLGvt1lDoaK68efP2BI,47565
51
+ modal/functions.pyi,sha256=pxTuV31WW1SuRNXTm4CMp7s_tssbjj9jPhnY3TroVag,47565
52
52
  modal/image.py,sha256=c0lUSAoU-Ip3g5DGZ0uhdCzoWSQWh1g0i-7Rxo-Sz-I,160
53
53
  modal/image.pyi,sha256=Whbfmda2YLAyzctLEF9uF4FQ5b1canwLojSksRJ4gx8,59716
54
54
  modal/io_streams.py,sha256=3fhhb7SDJ69pVUu9J3PiMLBePD9bpiIxPN05SCzf8FE,29118
@@ -73,8 +73,8 @@ modal/retries.py,sha256=tSGB5bGM5xZZUDXMkuelIEoQJY0vOukOssZhwc6tXAo,5014
73
73
  modal/runner.py,sha256=YdBqWOWkcGgSDKLEz1zrGNHrh0-d2tSNx24XPB6QyoM,30284
74
74
  modal/runner.pyi,sha256=0hIfkl-7VTyw1n-1B0AV7f53t3i3hCzRPyBu3DUyHnk,9669
75
75
  modal/running_app.py,sha256=xSR1VVlhxEFytmjx2x697_0GpD25Vc9crhp6r117_QY,1145
76
- modal/sandbox.py,sha256=Eh0gxGZUfDBkPlAq0f8irp9hNAajaQWVSjyj02wDkSU,107078
77
- modal/sandbox.pyi,sha256=aARprjklTBoyGhOGqdS7vTa-VddPmM59j1lnBBnUZeY,124147
76
+ modal/sandbox.py,sha256=Pb_rqjAkEIlIl_ewgbKzj6kKMDPAJdv9JiVbSZKj5hU,109254
77
+ modal/sandbox.pyi,sha256=vF1qXdslQeZDrlLTgw5q0F3jtjmTMz9USy-ggQiJiO8,126252
78
78
  modal/sandbox_fs.py,sha256=Iwx-kjWrp12Gii_8Zdo1T8DHOkkbO0n9RMyBuYXMkU4,31361
79
79
  modal/sandbox_fs.pyi,sha256=nmfb1Ns9__C5sH3Mq52rFDtJbfKdQrn7Cc1mcP64WBw,46902
80
80
  modal/schedule.py,sha256=3F15Vh4g8C34jGcO-vgFkBHZl7XvP7qieXayQ9gKsyw,3248
@@ -101,7 +101,7 @@ modal/_output/rich.py,sha256=x3PQKzIt_HBbaHOyzsN8gbuS1QsR7eFVD3Bo3GthXss,31845
101
101
  modal/_output/status.py,sha256=c0rdvjoYKtIG7XJqq42TlcKawkYqZWtod38RmRY5IWA,4492
102
102
  modal/_runtime/__init__.py,sha256=MIEP8jhXUeGq_eCjYFcqN5b1bxBM4fdk0VESpjWR0fc,28
103
103
  modal/_runtime/asgi.py,sha256=eDNPsmV6SXl0CwUqgy7yrFDaPdlx4NiWTScXpCTlBFQ,22805
104
- modal/_runtime/container_io_manager.py,sha256=gwoe2zdWYCuZnTAUmVLOlRwsdC2yop6JWdSa6sBeQYs,46013
104
+ modal/_runtime/container_io_manager.py,sha256=Mn0YzfpG0cALpc7vi5F1OIMiRSiA1s7d2sXv083AUps,46046
105
105
  modal/_runtime/container_io_manager.pyi,sha256=Wj2JA-EizzOGyrpR-GJuH97KDtyHAAspSsU-WJGDo4c,20050
106
106
  modal/_runtime/execution_context.py,sha256=zsPsVOryok4Bgsi_T19dX6ro7JUnqJeNV1_esjI5JfM,3730
107
107
  modal/_runtime/execution_context.pyi,sha256=i30NeuFxr7wcaqIUnLN9-fh_LqpcMe-KZ6Cn0VXZvcU,2569
@@ -115,7 +115,7 @@ modal/_utils/__init__.py,sha256=waLjl5c6IPDhSsdWAm9Bji4e2PVxamYABKAze6CHVXY,28
115
115
  modal/_utils/app_utils.py,sha256=88BT4TPLWfYAQwKTHcyzNQRHg8n9B-QE2UyJs96iV-0,108
116
116
  modal/_utils/async_utils.py,sha256=4E4i5bReO4NudEwi8zT9kTDKwZsQeuMOFC5O8Rz9_E4,45838
117
117
  modal/_utils/auth_token_manager.py,sha256=J3EG8lMLUe2t_sHQ0gllj5qQi6j2SpStnMEh9JV4NCk,5124
118
- modal/_utils/blob_utils.py,sha256=8ESgmhIH1Rh28mr0B05msp9yU5NmRhoTqxswgVoLhR8,25683
118
+ modal/_utils/blob_utils.py,sha256=VUYGmrRqmjdsjOEDcqIDeWONouVI4CzL-Rrcn8skNXs,26010
119
119
  modal/_utils/browser_utils.py,sha256=Yqq0qU4Id6oaDOdeT1JEmbCN7vj4baNJJraJhRWU8ZI,1085
120
120
  modal/_utils/bytes_io_segment_payload.py,sha256=MFe0hs9pSskRLL6iX0vV7bJ_oG-VwIC98oNB3EpsW2w,4272
121
121
  modal/_utils/curl_utils.py,sha256=cZey1GZzyCRafXW4kje1rm739S0rc0TuY6CLG5U_zI8,3447
@@ -193,7 +193,7 @@ modal/experimental/flash.py,sha256=GAJ1c-EGL8M3_loAkqr5gdUfySMHY3U_oc6RywfZ8-0,3
193
193
  modal/experimental/flash.pyi,sha256=lpTqJFZRMGWscw0xpYZVdBMnAYjj16asXE4_64A6itQ,17774
194
194
  modal/experimental/ipython.py,sha256=kJ6o9wkAY_MiSb7paewI7f1MJAeqdi8TX5pBdhr_mUI,2925
195
195
  modal/skills/modal/SKILL.md,sha256=WzLjYJ1utjc_ZOf6qZTPwB6wxxwRYB5PibdvIf_FLy0,5316
196
- modal-1.5.2.dev3.dist-info/licenses/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
196
+ modal-1.5.2.dev5.dist-info/licenses/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
197
197
  modal_docs/__init__.py,sha256=svYKtV8HDwDCN86zbdWqyq5T8sMdGDj0PVlzc2tIxDM,28
198
198
  modal_docs/gen_cli_docs.py,sha256=nZRXP6sh0hTFqTQOo_dMKy8V57I-L6V5cv3cs3eL7NE,5808
199
199
  modal_docs/gen_cli_docs_main.py,sha256=UPGr7O1DYTIRLwfINe2rbdh89J3cPVTU1OWL-SjxnOQ,198
@@ -216,10 +216,10 @@ modal_proto/task_command_router_pb2.py,sha256=A-Q_mi-Wf761JNtcOmUkoWsPpIuYiGYcoK
216
216
  modal_proto/task_command_router_pb2.pyi,sha256=-0UrXDxiTvIy_BUP7OGeGNeLVaTWPHWDSaES4FVMYyw,42841
217
217
  modal_proto/task_command_router_pb2_grpc.py,sha256=QM5h4IvjweLZ6ZRyJD5AB8juzw4anhj4hzPS8mE1mWM,38611
218
218
  modal_proto/task_command_router_pb2_grpc.pyi,sha256=jLJvR5sZmKqU_3pTul-Mgfc7WcG5gQjvHS9CbACpFIU,12602
219
- modal_version/__init__.py,sha256=LE5HqLHa8MaxjQHJFD3E66__uYN-eES_OjuXHNrB4TM,120
219
+ modal_version/__init__.py,sha256=zJasD63IVnWBdrYwCLFH_o6sXGX4qdIQPNV2rLclhFQ,120
220
220
  modal_version/__main__.py,sha256=nLUbubxKx7GXNzJIkTB7M7_u8080LyLM0IS0rzFkC_c,119
221
- modal-1.5.2.dev3.dist-info/METADATA,sha256=9JAyU5gZxJTNijv3uaee68K9yAAQiLONV6duKrJTppQ,2512
222
- modal-1.5.2.dev3.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
223
- modal-1.5.2.dev3.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
224
- modal-1.5.2.dev3.dist-info/top_level.txt,sha256=4BWzoKYREKUZ5iyPzZpjqx4G8uB5TWxXPDwibLcVa7k,43
225
- modal-1.5.2.dev3.dist-info/RECORD,,
221
+ modal-1.5.2.dev5.dist-info/METADATA,sha256=69zEZi2xYO3kPZDStB0XqIlBsmqJCJ409PV8kkgFsyY,2512
222
+ modal-1.5.2.dev5.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
223
+ modal-1.5.2.dev5.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
224
+ modal-1.5.2.dev5.dist-info/top_level.txt,sha256=4BWzoKYREKUZ5iyPzZpjqx4G8uB5TWxXPDwibLcVa7k,43
225
+ modal-1.5.2.dev5.dist-info/RECORD,,
modal_version/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
1
  # Copyright Modal Labs 2026
2
2
  """Supplies the current version of the modal client library."""
3
3
 
4
- __version__ = "1.5.2.dev3"
4
+ __version__ = "1.5.2.dev5"