modal 1.1.2.dev35__py3-none-any.whl → 1.1.2.dev37__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.
modal/_functions.py CHANGED
@@ -1564,12 +1564,13 @@ Use the `Function.get_web_url()` method instead.
1564
1564
  raise InvalidError("A generator function cannot be called with `.spawn_map(...)`.")
1565
1565
 
1566
1566
  assert self._function_name
1567
- function_call_id = await _spawn_map_invocation(
1567
+ function_call_id, num_inputs = await _spawn_map_invocation(
1568
1568
  self,
1569
1569
  input_queue,
1570
1570
  self.client,
1571
1571
  )
1572
- fc: _FunctionCall[ReturnType] = _FunctionCall._new_hydrated(function_call_id, self.client, None)
1572
+ metadata = api_pb2.FunctionCallFromIdResponse(function_call_id=function_call_id, num_inputs=num_inputs)
1573
+ fc: _FunctionCall[ReturnType] = _FunctionCall._new_hydrated(function_call_id, self.client, metadata)
1573
1574
  return fc
1574
1575
 
1575
1576
  async def _call_function(self, args, kwargs) -> ReturnType:
@@ -1833,10 +1834,24 @@ class _FunctionCall(typing.Generic[ReturnType], _Object, type_prefix="fc"):
1833
1834
  """
1834
1835
 
1835
1836
  _is_generator: bool = False
1837
+ _num_inputs: Optional[int] = None
1836
1838
 
1837
1839
  def _invocation(self):
1838
1840
  return _Invocation(self.client.stub, self.object_id, self.client)
1839
1841
 
1842
+ def _hydrate_metadata(self, metadata: Optional[Message]):
1843
+ if not metadata:
1844
+ return
1845
+ assert isinstance(metadata, api_pb2.FunctionCallFromIdResponse)
1846
+ self._num_inputs = metadata.num_inputs
1847
+
1848
+ @live_method
1849
+ async def num_inputs(self) -> int:
1850
+ """Get the number of inputs in the function call."""
1851
+ # Should have been hydrated.
1852
+ assert self._num_inputs is not None
1853
+ return self._num_inputs
1854
+
1840
1855
  async def get(self, timeout: Optional[float] = None, *, index: int = 0) -> ReturnType:
1841
1856
  """Get the result of the index-th input of the function call.
1842
1857
  `.spawn()` calls have a single output, so only specifying `index=0` is valid.
@@ -1902,7 +1917,15 @@ class _FunctionCall(typing.Generic[ReturnType], _Object, type_prefix="fc"):
1902
1917
  if client is None:
1903
1918
  client = await _Client.from_env()
1904
1919
 
1905
- fc: _FunctionCall[Any] = _FunctionCall._new_hydrated(function_call_id, client, None)
1920
+ async def _load(self: _FunctionCall, resolver: Resolver, existing_object_id: Optional[str]):
1921
+ request = api_pb2.FunctionCallFromIdRequest(function_call_id=function_call_id)
1922
+ resp = await retry_transient_errors(resolver.client.stub.FunctionCallFromId, request)
1923
+ self._hydrate(function_call_id, resolver.client, resp)
1924
+
1925
+ rep = f"FunctionCall.from_id({function_call_id!r})"
1926
+ fc: _FunctionCall[Any] = _FunctionCall._from_loader(_load, rep, hydrate_lazily=True)
1927
+ # We already know the object ID, so we can set it directly
1928
+ fc._object_id = function_call_id
1906
1929
  return fc
1907
1930
 
1908
1931
  @staticmethod
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.2.dev35",
36
+ version: str = "1.1.2.dev37",
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.2.dev35",
167
+ version: str = "1.1.2.dev37",
168
168
  ):
169
169
  """mdmd:hidden
170
170
  The Modal client object is not intended to be instantiated directly by users.
modal/file_io.py CHANGED
@@ -128,7 +128,7 @@ class _FileIO(Generic[T]):
128
128
 
129
129
  **Usage**
130
130
 
131
- ```python
131
+ ```python notest
132
132
  import modal
133
133
 
134
134
  app = modal.App.lookup("my-app", create_if_missing=True)
modal/file_io.pyi CHANGED
@@ -62,7 +62,7 @@ class _FileIO(typing.Generic[T]):
62
62
 
63
63
  **Usage**
64
64
 
65
- ```python
65
+ ```python notest
66
66
  import modal
67
67
 
68
68
  app = modal.App.lookup("my-app", create_if_missing=True)
@@ -232,7 +232,7 @@ class FileIO(typing.Generic[T]):
232
232
 
233
233
  **Usage**
234
234
 
235
- ```python
235
+ ```python notest
236
236
  import modal
237
237
 
238
238
  app = modal.App.lookup("my-app", create_if_missing=True)
modal/functions.pyi CHANGED
@@ -738,12 +738,25 @@ class FunctionCall(typing.Generic[modal._functions.ReturnType], modal.object.Obj
738
738
  """
739
739
 
740
740
  _is_generator: bool
741
+ _num_inputs: typing.Optional[int]
741
742
 
742
743
  def __init__(self, *args, **kwargs):
743
744
  """mdmd:hidden"""
744
745
  ...
745
746
 
746
747
  def _invocation(self): ...
748
+ def _hydrate_metadata(self, metadata: typing.Optional[google.protobuf.message.Message]): ...
749
+
750
+ class __num_inputs_spec(typing_extensions.Protocol[SUPERSELF]):
751
+ def __call__(self, /) -> int:
752
+ """Get the number of inputs in the function call."""
753
+ ...
754
+
755
+ async def aio(self, /) -> int:
756
+ """Get the number of inputs in the function call."""
757
+ ...
758
+
759
+ num_inputs: __num_inputs_spec[typing_extensions.Self]
747
760
 
748
761
  class __get_spec(typing_extensions.Protocol[ReturnType_INNER, SUPERSELF]):
749
762
  def __call__(self, /, timeout: typing.Optional[float] = None, *, index: int = 0) -> ReturnType_INNER:
modal/parallel_map.py CHANGED
@@ -271,10 +271,21 @@ class AsyncInputPumper(InputPumper):
271
271
  ):
272
272
  super().__init__(client, input_queue=input_queue, function=function, function_call_id=function_call_id)
273
273
 
274
+ async def pump_inputs(self):
275
+ async for _ in super().pump_inputs():
276
+ pass
277
+ request = api_pb2.FunctionFinishInputsRequest(
278
+ function_id=self.function.object_id,
279
+ function_call_id=self.function_call_id,
280
+ num_inputs=self.inputs_sent,
281
+ )
282
+ await retry_transient_errors(self.client.stub.FunctionFinishInputs, request, max_retries=None)
283
+ yield
284
+
274
285
 
275
286
  async def _spawn_map_invocation(
276
287
  function: "modal.functions._Function", raw_input_queue: _SynchronizedQueue, client: "modal.client._Client"
277
- ) -> str:
288
+ ) -> tuple[str, int]:
278
289
  assert client.stub
279
290
  request = api_pb2.FunctionMapRequest(
280
291
  function_id=function.object_id,
@@ -340,7 +351,7 @@ async def _spawn_map_invocation(
340
351
  )
341
352
  log_debug_stats_task.cancel()
342
353
  await log_debug_stats_task
343
- return function_call_id
354
+ return function_call_id, inputs_created
344
355
 
345
356
 
346
357
  async def _map_invocation(
modal/parallel_map.pyi CHANGED
@@ -136,9 +136,11 @@ class AsyncInputPumper(InputPumper):
136
136
  """Initialize self. See help(type(self)) for accurate signature."""
137
137
  ...
138
138
 
139
+ def pump_inputs(self): ...
140
+
139
141
  async def _spawn_map_invocation(
140
142
  function: modal._functions._Function, raw_input_queue: _SynchronizedQueue, client: modal.client._Client
141
- ) -> str: ...
143
+ ) -> tuple[str, int]: ...
142
144
  def _map_invocation(
143
145
  function: modal._functions._Function,
144
146
  raw_input_queue: _SynchronizedQueue,
modal/sandbox.py CHANGED
@@ -296,8 +296,9 @@ class _Sandbox(_Object, type_prefix="sb"):
296
296
  environment_name: Optional[str] = None, # *DEPRECATED* Optionally override the default environment
297
297
  ) -> "_Sandbox":
298
298
  """
299
- Create a new Sandbox to run untrusted, arbitrary code. The Sandbox's corresponding container
300
- will be created asynchronously.
299
+ Create a new Sandbox to run untrusted, arbitrary code.
300
+
301
+ The Sandbox's corresponding container will be created asynchronously.
301
302
 
302
303
  **Usage**
303
304
 
modal/sandbox.pyi CHANGED
@@ -120,8 +120,9 @@ class _Sandbox(modal._object._Object):
120
120
  client: typing.Optional[modal.client._Client] = None,
121
121
  environment_name: typing.Optional[str] = None,
122
122
  ) -> _Sandbox:
123
- """Create a new Sandbox to run untrusted, arbitrary code. The Sandbox's corresponding container
124
- will be created asynchronously.
123
+ """Create a new Sandbox to run untrusted, arbitrary code.
124
+
125
+ The Sandbox's corresponding container will be created asynchronously.
125
126
 
126
127
  **Usage**
127
128
 
@@ -432,8 +433,9 @@ class Sandbox(modal.object.Object):
432
433
  client: typing.Optional[modal.client.Client] = None,
433
434
  environment_name: typing.Optional[str] = None,
434
435
  ) -> Sandbox:
435
- """Create a new Sandbox to run untrusted, arbitrary code. The Sandbox's corresponding container
436
- will be created asynchronously.
436
+ """Create a new Sandbox to run untrusted, arbitrary code.
437
+
438
+ The Sandbox's corresponding container will be created asynchronously.
437
439
 
438
440
  **Usage**
439
441
 
@@ -482,8 +484,9 @@ class Sandbox(modal.object.Object):
482
484
  client: typing.Optional[modal.client.Client] = None,
483
485
  environment_name: typing.Optional[str] = None,
484
486
  ) -> Sandbox:
485
- """Create a new Sandbox to run untrusted, arbitrary code. The Sandbox's corresponding container
486
- will be created asynchronously.
487
+ """Create a new Sandbox to run untrusted, arbitrary code.
488
+
489
+ The Sandbox's corresponding container will be created asynchronously.
487
490
 
488
491
  **Usage**
489
492
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.1.2.dev35
3
+ Version: 1.1.2.dev37
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=zmrKbptRbqp4euS3LWncKaLXb8Kjj4YreusOzpEpRMk,2856
4
4
  modal/_clustered_functions.pyi,sha256=_wtFjWocGf1WgI-qYBpbJPArNkg2H9JV7BVaGgMesEQ,1103
5
5
  modal/_container_entrypoint.py,sha256=3zNp7ahgoRf1Nw2pOrTPvcJyuctsU0DP8JIFQMZz-cc,28581
6
- modal/_functions.py,sha256=5DZsmmGiGzbs6WT-a_fQrcEfEhZ5QaiVF95xT67k8Lc,84088
6
+ modal/_functions.py,sha256=0ZOmu5koDpnVLMuoajf5LVTiiJjopsSm8OFMzm4gCYI,85237
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
@@ -22,7 +22,7 @@ modal/app.py,sha256=NIkdg9tTBsB8xWEOpU8GSpUfHeGleA4M9MQ77PKADok,48052
22
22
  modal/app.pyi,sha256=k0HnXfwV3mEze3PFHmSeqXBqizNqeJWF5oxrqo-P4Wg,43447
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=-hgKLgjKc78yjRuWJ0hViZ5zjw22BcACy3CjRlv8V-E,15831
25
+ modal/client.pyi,sha256=HulveXZH-cdI5MzROuLNBqK1lFLBjn8s9EkmicvIXKA,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
28
  modal/cls.py,sha256=1mBcExFrLDTZwkD3Dzu8F26_CL0CGktOV9pE60Y8g_E,40689
@@ -35,11 +35,11 @@ modal/dict.pyi,sha256=F9yxTgBjxLOy6boB3N4wc2BtnGIO1TARmyhpMBC8c80,33317
35
35
  modal/environments.py,sha256=gHFNLG78bqgizpQ4w_elz27QOqmcgAonFsmLs7NjUJ4,6804
36
36
  modal/environments.pyi,sha256=9-KtrzAcUe55cCP4020lSUD7-fWS7OPakAHssq4-bro,4219
37
37
  modal/exception.py,sha256=o0V93PK8Hcg2YQ2aeOB1Y-qWBw4Gz5ATfyokR8GapuQ,5634
38
- modal/file_io.py,sha256=BVqAJ0sgPUfN8QsYztWiGB4j56he60TncM02KsylnCw,21449
39
- modal/file_io.pyi,sha256=cPT_hsplE5iLCXhYOLn1Sp9eDdk7DxdFmicQHanJZyg,15918
38
+ modal/file_io.py,sha256=OSKr77TujcXGJW1iikzYiHckLSmv07QBgBHcxxYEkoI,21456
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=FdEeGqwysl83CpOrYWOk2EfazYhl8Ar4GIF_KQN19Qo,36633
42
+ modal/functions.pyi,sha256=Ne47_rO_hc8PJq-JxgsFLiN09GeBnjEx-7ME70PQ_Ik,37136
43
43
  modal/gpu.py,sha256=Fe5ORvVPDIstSq1xjmM6OoNgLYFWvogP9r5BgmD3hYg,6769
44
44
  modal/image.py,sha256=A83nmo0zfCUwgvJh0LZ7Yc1sYvDnZLl_phbKxN-9HIw,103144
45
45
  modal/image.pyi,sha256=oH-GCHVEwD5fOX0K_IaWN5RKZlYwX82z-K4wxx8aN3c,68541
@@ -52,8 +52,8 @@ modal/network_file_system.pyi,sha256=Td_IobHr84iLo_9LZKQ4tNdUB60yjX8QWBaFiUvhfi8
52
52
  modal/object.py,sha256=bTeskuY8JFrESjU4_UL_nTwYlBQdOLmVaOX3X6EMxsg,164
53
53
  modal/object.pyi,sha256=qlyVVMezW3XgJe_iqhtzWRSki3Nuk-KrpXc1g-r8ujA,6944
54
54
  modal/output.py,sha256=q4T9uHduunj4NwY-YSwkHGgjZlCXMuJbfQ5UFaAGRAc,1968
55
- modal/parallel_map.py,sha256=2ujy7eRHK7N2sdyoKjq_ynWUyeoN9M9BD5XpB3KjMLk,66948
56
- modal/parallel_map.pyi,sha256=MMjGNm-Q4J_rhjZ3441WOvQn4yrs0l0nACiKublZdu8,15373
55
+ modal/parallel_map.py,sha256=Q2srzzDcwE5uWSSzA80_Y3NBUoCHUFAP2Ekz-Zi7jn0,67397
56
+ modal/parallel_map.pyi,sha256=PTNIX3_KXLpEIGiFmZ5R5_G3a2toUvFdiUZVdSHa060,15417
57
57
  modal/partial_function.py,sha256=aIdlGfTjjgqY6Fpr-biCjvRU9W542_S5N2xkNN_rYGM,1127
58
58
  modal/partial_function.pyi,sha256=lqqOzZ9-QvHTDWKQ_oAYYOvsXgTOBKhO9u-RI98JbUk,13986
59
59
  modal/proxy.py,sha256=CQydu_NPDgApN2GLdd7rrcg8PM-pXyFdVYcTaGMBRCQ,1491
@@ -65,8 +65,8 @@ modal/retries.py,sha256=IvNLDM0f_GLUDD5VgEDoN09C88yoxSrCquinAuxT1Sc,5205
65
65
  modal/runner.py,sha256=ostdzYpQb-20tlD6dIq7bpWTkZkOhjJBNuMNektqnJA,24068
66
66
  modal/runner.pyi,sha256=lbwLljm1cC8d6PcNvmYQhkE8501V9fg0bYqqKX6G4r4,8489
67
67
  modal/running_app.py,sha256=v61mapYNV1-O-Uaho5EfJlryMLvIT9We0amUOSvSGx8,1188
68
- modal/sandbox.py,sha256=eQd0Cf9yTFCNshnj7oH8WvecbhVIwsEsmuXB9O-REis,40927
69
- modal/sandbox.pyi,sha256=_ddnvZGauSRG-WelsMB5oPil8KVWb0PSvmuAzAzrLIw,41713
68
+ modal/sandbox.py,sha256=FSZxvgJ2mf93YCgXasqLA2KFt3uHI8WiY33Drh-GDwk,40928
69
+ modal/sandbox.pyi,sha256=-rPSoMAu63B5BkOfdl5yiwX0WrpJ_b12EHU--ovnq-g,41716
70
70
  modal/schedule.py,sha256=ng0g0AqNY5GQI9KhkXZQ5Wam5G42glbkqVQsNpBtbDE,3078
71
71
  modal/scheduler_placement.py,sha256=BAREdOY5HzHpzSBqt6jDVR6YC_jYfHMVqOzkyqQfngU,1235
72
72
  modal/secret.py,sha256=Y6vMT7PUFdwCjVqAe9efxbVwKNjLk2yMLDV3HdnbdxI,18483
@@ -153,7 +153,7 @@ modal/experimental/__init__.py,sha256=dPBPpxsmjZMLF3YjRrXoTvT01pl65wxi4UdFZsOem3
153
153
  modal/experimental/flash.py,sha256=viXQumCIFp5VFsPFURdFTBTjP_QnsAi8nSWXAMmfjeQ,19744
154
154
  modal/experimental/flash.pyi,sha256=A8_qJGtGoXEzKDdHbvhmCw7oqfneFEvJQK3ZdTOvUdU,10830
155
155
  modal/experimental/ipython.py,sha256=TrCfmol9LGsRZMeDoeMPx3Hv3BFqQhYnmD_iH0pqdhk,2904
156
- modal-1.1.2.dev35.dist-info/licenses/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
156
+ modal-1.1.2.dev37.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=rH9A22xBt4u3QXrGTl1F14h6atSOI0HKOoXqtx__ncA,121
179
+ modal_version/__init__.py,sha256=8-JPqd4uMt_DmBImkPEOPpib0TVz5Wy0lCbu3rYGaNk,121
180
180
  modal_version/__main__.py,sha256=2FO0yYQQwDTh6udt1h-cBnGd1c4ZyHnHSI4BksxzVac,105
181
- modal-1.1.2.dev35.dist-info/METADATA,sha256=64VgIKamORGJ9j88hpj4BUSAGWnctfOOPbjew7rOAjw,2460
182
- modal-1.1.2.dev35.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
183
- modal-1.1.2.dev35.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
184
- modal-1.1.2.dev35.dist-info/top_level.txt,sha256=4BWzoKYREKUZ5iyPzZpjqx4G8uB5TWxXPDwibLcVa7k,43
185
- modal-1.1.2.dev35.dist-info/RECORD,,
181
+ modal-1.1.2.dev37.dist-info/METADATA,sha256=MoOdHAX5l3BjeObbFRG0OhMHPrwW2TMfp0phlYv5ecQ,2460
182
+ modal-1.1.2.dev37.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
183
+ modal-1.1.2.dev37.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
184
+ modal-1.1.2.dev37.dist-info/top_level.txt,sha256=4BWzoKYREKUZ5iyPzZpjqx4G8uB5TWxXPDwibLcVa7k,43
185
+ modal-1.1.2.dev37.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.2.dev35"
4
+ __version__ = "1.1.2.dev37"