modal 0.73.25__py3-none-any.whl → 0.73.27__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.
@@ -322,6 +322,16 @@ def call_function(
322
322
  user_code_event_loop.run(run_concurrent_inputs())
323
323
  else:
324
324
  for io_context in container_io_manager.run_inputs_outputs(finalized_functions, batch_max_size, batch_wait_ms):
325
+ # This goes to a registered signal handler for sync Modal functions, or to the
326
+ # `UserCodeEventLoop` for async functions.
327
+ #
328
+ # We only send this signal on functions that do not have concurrent inputs enabled.
329
+ # This allows us to do fine-grained input cancellation. On sync functions, the
330
+ # SIGUSR1 signal should interrupt the main thread where user code is running,
331
+ # raising an InputCancellation() exception. On async functions, the signal should
332
+ # reach a handler in UserCodeEventLoop, which cancels the task.
333
+ io_context.set_cancel_callback(lambda: os.kill(os.getpid(), signal.SIGUSR1))
334
+
325
335
  if io_context.finalized_function.is_async:
326
336
  user_code_event_loop.run(run_input_async(io_context))
327
337
  else:
modal/_functions.py CHANGED
@@ -1089,6 +1089,17 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
1089
1089
  f = modal.Function.from_name("other-app", "function")
1090
1090
  ```
1091
1091
  """
1092
+ if "." in name:
1093
+ class_name, method_name = name.split(".", 1)
1094
+ deprecation_warning(
1095
+ (2025, 2, 6),
1096
+ "Looking up class methods using Function.from_name will be deprecated"
1097
+ " in a future version of Modal.\nUse modal.Cls.from_name instead, e.g.\n\n"
1098
+ f'{class_name} = modal.Cls.from_name("{app_name}", "{class_name}")\n'
1099
+ f"instance = {class_name}(...)\n"
1100
+ f"instance.{method_name}.remote(...)\n",
1101
+ pending=True,
1102
+ )
1092
1103
 
1093
1104
  async def _load_remote(self: _Function, resolver: Resolver, existing_object_id: Optional[str]):
1094
1105
  assert resolver.client and resolver.client.stub
@@ -5,7 +5,6 @@ import inspect
5
5
  import json
6
6
  import math
7
7
  import os
8
- import signal
9
8
  import sys
10
9
  import time
11
10
  import traceback
@@ -382,22 +381,9 @@ class _ContainerIOManager:
382
381
  # response.cancel_input_event.terminate_containers is never set, the server gets the worker to handle it.
383
382
  input_ids_to_cancel = response.cancel_input_event.input_ids
384
383
  if input_ids_to_cancel:
385
- if self._max_concurrency > 1:
386
- for input_id in input_ids_to_cancel:
387
- if input_id in self.current_inputs:
388
- self.current_inputs[input_id].cancel()
389
-
390
- elif self.current_input_id and self.current_input_id in input_ids_to_cancel:
391
- # This goes to a registered signal handler for sync Modal functions, or to the
392
- # `SignalHandlingEventLoop` for async functions.
393
- #
394
- # We only send this signal on functions that do not have concurrent inputs enabled.
395
- # This allows us to do fine-grained input cancellation. On sync functions, the
396
- # SIGUSR1 signal should interrupt the main thread where user code is running,
397
- # raising an InputCancellation() exception. On async functions, the signal should
398
- # reach a handler in SignalHandlingEventLoop, which cancels the task.
399
- logger.warning(f"Received a cancellation signal while processing input {self.current_input_id}")
400
- os.kill(os.getpid(), signal.SIGUSR1)
384
+ for input_id in input_ids_to_cancel:
385
+ if input_id in self.current_inputs:
386
+ self.current_inputs[input_id].cancel()
401
387
  return True
402
388
  return False
403
389
 
modal/client.pyi CHANGED
@@ -27,7 +27,7 @@ class _Client:
27
27
  _snapshotted: bool
28
28
 
29
29
  def __init__(
30
- self, server_url: str, client_type: int, credentials: typing.Optional[tuple[str, str]], version: str = "0.73.25"
30
+ self, server_url: str, client_type: int, credentials: typing.Optional[tuple[str, str]], version: str = "0.73.27"
31
31
  ): ...
32
32
  def is_closed(self) -> bool: ...
33
33
  @property
@@ -85,7 +85,7 @@ class Client:
85
85
  _snapshotted: bool
86
86
 
87
87
  def __init__(
88
- self, server_url: str, client_type: int, credentials: typing.Optional[tuple[str, str]], version: str = "0.73.25"
88
+ self, server_url: str, client_type: int, credentials: typing.Optional[tuple[str, str]], version: str = "0.73.27"
89
89
  ): ...
90
90
  def is_closed(self) -> bool: ...
91
91
  @property
modal/functions.pyi CHANGED
@@ -200,11 +200,11 @@ class Function(
200
200
 
201
201
  _call_generator_nowait: ___call_generator_nowait_spec[typing_extensions.Self]
202
202
 
203
- class __remote_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER, SUPERSELF]):
203
+ class __remote_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER, SUPERSELF]):
204
204
  def __call__(self, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> ReturnType_INNER: ...
205
205
  async def aio(self, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> ReturnType_INNER: ...
206
206
 
207
- remote: __remote_spec[modal._functions.P, modal._functions.ReturnType, typing_extensions.Self]
207
+ remote: __remote_spec[modal._functions.ReturnType, modal._functions.P, typing_extensions.Self]
208
208
 
209
209
  class __remote_gen_spec(typing_extensions.Protocol[SUPERSELF]):
210
210
  def __call__(self, *args, **kwargs) -> typing.Generator[typing.Any, None, None]: ...
@@ -219,19 +219,19 @@ class Function(
219
219
  self, *args: modal._functions.P.args, **kwargs: modal._functions.P.kwargs
220
220
  ) -> modal._functions.OriginalReturnType: ...
221
221
 
222
- class ___experimental_spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER, SUPERSELF]):
222
+ class ___experimental_spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER, SUPERSELF]):
223
223
  def __call__(self, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]: ...
224
224
  async def aio(self, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]: ...
225
225
 
226
226
  _experimental_spawn: ___experimental_spawn_spec[
227
- modal._functions.P, modal._functions.ReturnType, typing_extensions.Self
227
+ modal._functions.ReturnType, modal._functions.P, typing_extensions.Self
228
228
  ]
229
229
 
230
- class __spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER, SUPERSELF]):
230
+ class __spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER, SUPERSELF]):
231
231
  def __call__(self, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]: ...
232
232
  async def aio(self, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]: ...
233
233
 
234
- spawn: __spawn_spec[modal._functions.P, modal._functions.ReturnType, typing_extensions.Self]
234
+ spawn: __spawn_spec[modal._functions.ReturnType, modal._functions.P, typing_extensions.Self]
235
235
 
236
236
  def get_raw_f(self) -> collections.abc.Callable[..., typing.Any]: ...
237
237
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: modal
3
- Version: 0.73.25
3
+ Version: 0.73.27
4
4
  Summary: Python client library for Modal
5
5
  Author: Modal Labs
6
6
  Author-email: support@modal.com
@@ -2,8 +2,8 @@ modal/__init__.py,sha256=df6aKAigSPFXnmIohWySf_1zZ9Gzgrb7-oprSbopD4w,2299
2
2
  modal/__main__.py,sha256=scYhGFqh8OJcVDo-VOxIT6CCwxOgzgflYWMnIZiMRqE,2871
3
3
  modal/_clustered_functions.py,sha256=kTf-9YBXY88NutC1akI-gCbvf01RhMPCw-zoOI_YIUE,2700
4
4
  modal/_clustered_functions.pyi,sha256=vllkegc99A0jrUOWa8mdlSbdp6uz36TsHhGxysAOpaQ,771
5
- modal/_container_entrypoint.py,sha256=4z24Tait5ffMOMW4Uqwr4PQKh1eMemjI5CID3L5bvIQ,28588
6
- modal/_functions.py,sha256=EzTHyRmOFZ75gCuyAIYJDt5EmVW-YoHGLpFzU50WclE,71424
5
+ modal/_container_entrypoint.py,sha256=MlKDaCYso7cK3JxNmVErdm1ADdwK40HsPnrrJKCa8vk,29285
6
+ modal/_functions.py,sha256=N9Sp4SDv7oFung2abqy3VAaehaaWR9Y9SWxRlKLARI8,71984
7
7
  modal/_ipython.py,sha256=TW1fkVOmZL3YYqdS2YlM1hqpf654Yf8ZyybHdBnlhSw,301
8
8
  modal/_location.py,sha256=S3lSxIU3h9HkWpkJ3Pwo0pqjIOSB1fjeSgUsY3x7eec,1202
9
9
  modal/_object.py,sha256=ItQcsMNkz9Y3kdTsvfNarbW-paJ2qabDyQ7njaqY0XI,11359
@@ -21,7 +21,7 @@ modal/app.py,sha256=MaWCYgNx8y2GQhmaXQBMKKAAfCYfdxrdYs6zCBoJzwI,44628
21
21
  modal/app.pyi,sha256=lxiuWzE_OLb3WHg-H7Pek9DGBuCUzZ55P594VhJL5LA,26113
22
22
  modal/call_graph.py,sha256=1g2DGcMIJvRy-xKicuf63IVE98gJSnQsr8R_NVMptNc,2581
23
23
  modal/client.py,sha256=8SQawr7P1PNUCq1UmJMUQXG2jIo4Nmdcs311XqrNLRE,15276
24
- modal/client.pyi,sha256=dMogRnUnuDCHlwgwTRXIFzlY-nhL6_gPInyN-XDcYoo,7593
24
+ modal/client.pyi,sha256=NNU3kdFXj6deZST1JWu_j9164F4hiVkNeNtK9ltc4DE,7593
25
25
  modal/cloud_bucket_mount.py,sha256=YOe9nnvSr4ZbeCn587d7_VhE9IioZYRvF9VYQTQux08,5914
26
26
  modal/cloud_bucket_mount.pyi,sha256=30T3K1a89l6wzmEJ_J9iWv9SknoGqaZDx59Xs-ZQcmk,1607
27
27
  modal/cls.py,sha256=agxclIXZbzBbgcI5PPVD7IfOiHzv-B82xaaXtw9cpv8,31126
@@ -40,7 +40,7 @@ modal/file_io.py,sha256=lcMs_E9Xfm0YX1t9U2wNIBPnqHRxmImqjLW1GHqVmyg,20945
40
40
  modal/file_io.pyi,sha256=NTRft1tbPSWf9TlWVeZmTlgB5AZ_Zhu2srWIrWr7brk,9445
41
41
  modal/file_pattern_matcher.py,sha256=1cZ4V2wSLiaXqAqStETSwp3bzDD6QZOt6pmmjk3Okz4,6505
42
42
  modal/functions.py,sha256=kcNHvqeGBxPI7Cgd57NIBBghkfbeFJzXO44WW0jSmao,325
43
- modal/functions.pyi,sha256=avRIY0KOFky6tDRI5_SvnLXz7PUnG2H0hQA385cRtb0,14289
43
+ modal/functions.pyi,sha256=YflJx4BhzmJLJzpVWbuAMv0Qv63Mgb3r9qZqrgBEr1w,14289
44
44
  modal/gpu.py,sha256=uDluoK3hXyj2YRxGhVDFOifOBCsXFTo5hVueGoJPb8w,6001
45
45
  modal/image.py,sha256=KYc6bg-m9A6wiLF38dWcFBMrEATyR2KOF0sp-6O9uC0,91508
46
46
  modal/image.pyi,sha256=kdJzy1eaxNPZeCpE0TMYYLhJ6UWmkfRDeb_vzngJUoQ,26462
@@ -83,7 +83,7 @@ modal/volume.py,sha256=JAWeDvoAG95tMBv-fYIERyHsJPS_X_xGpxRRmYtb6j0,30096
83
83
  modal/volume.pyi,sha256=kTsXarphjZILXci84LQy7EyC84eXUs5-7D62IM5q3eE,12491
84
84
  modal/_runtime/__init__.py,sha256=MIEP8jhXUeGq_eCjYFcqN5b1bxBM4fdk0VESpjWR0fc,28
85
85
  modal/_runtime/asgi.py,sha256=vIxpGrCZhdeThwazQckmrqoNKgDQYOyv8emzBHr8CiU,22154
86
- modal/_runtime/container_io_manager.py,sha256=L6qv-Mo3mN3ttR5GX-G36cUhH_oz8wdP5WG0HT5FFzg,44619
86
+ modal/_runtime/container_io_manager.py,sha256=EHjdCky8RiM2kDpkwDhBqs2kCqC-ixc-TNS4X2eL8pg,43596
87
87
  modal/_runtime/execution_context.py,sha256=E6ofm6j1POXGPxS841X3V7JU6NheVb8OkQc7JpLq4Kg,2712
88
88
  modal/_runtime/gpu_memory_snapshot.py,sha256=tA3m1d1cwnmHpvpCeN_WijDd6n8byn7LWlpicbIxiOI,3144
89
89
  modal/_runtime/telemetry.py,sha256=T1RoAGyjBDr1swiM6pPsGRSITm7LI5FDK18oNXxY08U,5163
@@ -171,10 +171,10 @@ modal_proto/options_pb2_grpc.pyi,sha256=CImmhxHsYnF09iENPoe8S4J-n93jtgUYD2JPAc0y
171
171
  modal_proto/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
172
172
  modal_version/__init__.py,sha256=wiJQ53c-OMs0Xf1UeXOxQ7FwlV1VzIjnX6o-pRYZ_Pk,470
173
173
  modal_version/__main__.py,sha256=2FO0yYQQwDTh6udt1h-cBnGd1c4ZyHnHSI4BksxzVac,105
174
- modal_version/_version_generated.py,sha256=zOq6AT1-UlblI4Elu8MBUEnlgnjkHOuf6oOVKN4SW38,149
175
- modal-0.73.25.dist-info/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
176
- modal-0.73.25.dist-info/METADATA,sha256=ELZawxMX7dIgu5X25R7iqtkCN8m49WYpdh878J7Pykg,2330
177
- modal-0.73.25.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
178
- modal-0.73.25.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
179
- modal-0.73.25.dist-info/top_level.txt,sha256=1nvYbOSIKcmU50fNrpnQnrrOpj269ei3LzgB6j9xGqg,64
180
- modal-0.73.25.dist-info/RECORD,,
174
+ modal_version/_version_generated.py,sha256=sQVJ0gz9EdPuIRQye6HG69QC52sbpNWI8nHV1qb_C7o,149
175
+ modal-0.73.27.dist-info/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
176
+ modal-0.73.27.dist-info/METADATA,sha256=XbkIba_nQ8FVEZfNt6qn2LZA-gCZq42-zS5TtwNGrrg,2330
177
+ modal-0.73.27.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
178
+ modal-0.73.27.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
179
+ modal-0.73.27.dist-info/top_level.txt,sha256=1nvYbOSIKcmU50fNrpnQnrrOpj269ei3LzgB6j9xGqg,64
180
+ modal-0.73.27.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  # Copyright Modal Labs 2025
2
2
 
3
3
  # Note: Reset this value to -1 whenever you make a minor `0.X` release of the client.
4
- build_number = 25 # git: c61ef81
4
+ build_number = 27 # git: 4e70d23