modal 0.73.17__py3-none-any.whl → 0.73.18__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.
@@ -25,7 +25,7 @@ from google.protobuf.message import Message
25
25
 
26
26
  from modal._clustered_functions import initialize_clustered_function
27
27
  from modal._proxy_tunnel import proxy_tunnel
28
- from modal._serialization import deserialize, deserialize_proto_params
28
+ from modal._serialization import deserialize_params
29
29
  from modal._utils.async_utils import TaskContext, synchronizer
30
30
  from modal._utils.function_utils import (
31
31
  callable_has_non_self_params,
@@ -384,24 +384,6 @@ def call_lifecycle_functions(
384
384
  event_loop.run(res)
385
385
 
386
386
 
387
- def deserialize_params(serialized_params: bytes, function_def: api_pb2.Function, _client: "modal.client._Client"):
388
- if function_def.class_parameter_info.format in (
389
- api_pb2.ClassParameterInfo.PARAM_SERIALIZATION_FORMAT_UNSPECIFIED,
390
- api_pb2.ClassParameterInfo.PARAM_SERIALIZATION_FORMAT_PICKLE,
391
- ):
392
- # legacy serialization format - pickle of `(args, kwargs)` w/ support for modal object arguments
393
- param_args, param_kwargs = deserialize(serialized_params, _client)
394
- elif function_def.class_parameter_info.format == api_pb2.ClassParameterInfo.PARAM_SERIALIZATION_FORMAT_PROTO:
395
- param_args = ()
396
- param_kwargs = deserialize_proto_params(serialized_params, list(function_def.class_parameter_info.schema))
397
- else:
398
- raise ExecutionError(
399
- f"Unknown class parameter serialization format: {function_def.class_parameter_info.format}"
400
- )
401
-
402
- return param_args, param_kwargs
403
-
404
-
405
387
  def main(container_args: api_pb2.ContainerArguments, client: Client):
406
388
  # This is a bit weird but we need both the blocking and async versions of ContainerIOManager.
407
389
  # At some point, we should fix that by having built-in support for running "user code"
modal/_functions.py CHANGED
@@ -978,8 +978,6 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
978
978
  Binds a class-function to a specific instance of (init params, options) or a new workspace
979
979
  """
980
980
 
981
- # In some cases, reuse the base function, i.e. not create new clones of each method or the "service function"
982
- can_use_parent = len(args) + len(kwargs) == 0 and options is None
983
981
  parent = self
984
982
 
985
983
  async def _load(param_bound_func: _Function, resolver: Resolver, existing_object_id: Optional[str]):
@@ -999,11 +997,6 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
999
997
 
1000
998
  assert parent._client and parent._client.stub
1001
999
 
1002
- if can_use_parent:
1003
- # We can end up here if parent wasn't hydrated when class was instantiated, but has been since.
1004
- param_bound_func._hydrate_from_other(parent)
1005
- return
1006
-
1007
1000
  if (
1008
1001
  parent._class_parameter_info
1009
1002
  and parent._class_parameter_info.format == api_pb2.ClassParameterInfo.PARAM_SERIALIZATION_FORMAT_PROTO
@@ -1015,8 +1008,16 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
1015
1008
  "Use (<parameter_name>=value) keyword arguments when constructing classes instead."
1016
1009
  )
1017
1010
  serialized_params = serialize_proto_params(kwargs, parent._class_parameter_info.schema)
1011
+ can_use_parent = len(parent._class_parameter_info.schema) == 0
1018
1012
  else:
1013
+ can_use_parent = len(args) + len(kwargs) == 0 and options is None
1019
1014
  serialized_params = serialize((args, kwargs))
1015
+
1016
+ if can_use_parent:
1017
+ # We can end up here if parent wasn't hydrated when class was instantiated, but has been since.
1018
+ param_bound_func._hydrate_from_other(parent)
1019
+ return
1020
+
1020
1021
  environment_name = _get_environment_name(None, resolver)
1021
1022
  assert parent is not None and parent.is_hydrated
1022
1023
  req = api_pb2.FunctionBindParamsRequest(
@@ -1032,10 +1033,6 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
1032
1033
 
1033
1034
  fun: _Function = _Function._from_loader(_load, "Function(parametrized)", hydrate_lazily=True)
1034
1035
 
1035
- if can_use_parent and parent.is_hydrated:
1036
- # skip the resolver altogether:
1037
- fun._hydrate_from_other(parent)
1038
-
1039
1036
  fun._info = self._info
1040
1037
  fun._obj = obj
1041
1038
  return fun
modal/_serialization.py CHANGED
@@ -14,6 +14,9 @@ from .config import logger
14
14
  from .exception import DeserializationError, ExecutionError, InvalidError
15
15
  from .object import Object
16
16
 
17
+ if typing.TYPE_CHECKING:
18
+ import modal.client
19
+
17
20
  PICKLE_PROTOCOL = 4 # Support older Python versions.
18
21
 
19
22
 
@@ -454,3 +457,21 @@ def deserialize_proto_params(serialized_params: bytes, schema: list[api_pb2.Clas
454
457
  python_params[schema_param.name] = python_value
455
458
 
456
459
  return python_params
460
+
461
+
462
+ def deserialize_params(serialized_params: bytes, function_def: api_pb2.Function, _client: "modal.client._Client"):
463
+ if function_def.class_parameter_info.format in (
464
+ api_pb2.ClassParameterInfo.PARAM_SERIALIZATION_FORMAT_UNSPECIFIED,
465
+ api_pb2.ClassParameterInfo.PARAM_SERIALIZATION_FORMAT_PICKLE,
466
+ ):
467
+ # legacy serialization format - pickle of `(args, kwargs)` w/ support for modal object arguments
468
+ param_args, param_kwargs = deserialize(serialized_params, _client)
469
+ elif function_def.class_parameter_info.format == api_pb2.ClassParameterInfo.PARAM_SERIALIZATION_FORMAT_PROTO:
470
+ param_args = ()
471
+ param_kwargs = deserialize_proto_params(serialized_params, list(function_def.class_parameter_info.schema))
472
+ else:
473
+ raise ExecutionError(
474
+ f"Unknown class parameter serialization format: {function_def.class_parameter_info.format}"
475
+ )
476
+
477
+ return param_args, param_kwargs
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.17"
30
+ self, server_url: str, client_type: int, credentials: typing.Optional[tuple[str, str]], version: str = "0.73.18"
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.17"
88
+ self, server_url: str, client_type: int, credentials: typing.Optional[tuple[str, str]], version: str = "0.73.18"
89
89
  ): ...
90
90
  def is_closed(self) -> bool: ...
91
91
  @property
modal/cls.py CHANGED
@@ -182,6 +182,7 @@ class _Obj:
182
182
  def _get_parameter_values(self) -> dict[str, Any]:
183
183
  # binds args and kwargs according to the class constructor signature
184
184
  # (implicit by parameters or explicit)
185
+ # can only be called where the local definition exists
185
186
  sig = _get_class_constructor_signature(self._user_cls)
186
187
  bound_vars = sig.bind(*self._args, **self._kwargs)
187
188
  bound_vars.apply_defaults()
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
 
modal/partial_function.py CHANGED
@@ -26,13 +26,13 @@ MAX_BATCH_WAIT_MS = 10 * 60 * 1000 # 10 minutes
26
26
 
27
27
 
28
28
  class _PartialFunctionFlags(enum.IntFlag):
29
- FUNCTION: int = 1
30
- BUILD: int = 2
31
- ENTER_PRE_SNAPSHOT: int = 4
32
- ENTER_POST_SNAPSHOT: int = 8
33
- EXIT: int = 16
34
- BATCHED: int = 32
35
- CLUSTERED: int = 64 # Experimental: Clustered functions
29
+ FUNCTION = 1
30
+ BUILD = 2
31
+ ENTER_PRE_SNAPSHOT = 4
32
+ ENTER_POST_SNAPSHOT = 8
33
+ EXIT = 16
34
+ BATCHED = 32
35
+ CLUSTERED = 64 # Experimental: Clustered functions
36
36
 
37
37
  @staticmethod
38
38
  def all() -> int:
@@ -7,13 +7,13 @@ import typing
7
7
  import typing_extensions
8
8
 
9
9
  class _PartialFunctionFlags(enum.IntFlag):
10
- FUNCTION: int = 1
11
- BUILD: int = 2
12
- ENTER_PRE_SNAPSHOT: int = 4
13
- ENTER_POST_SNAPSHOT: int = 8
14
- EXIT: int = 16
15
- BATCHED: int = 32
16
- CLUSTERED: int = 64 # Experimental: Clustered functions
10
+ FUNCTION = 1
11
+ BUILD = 2
12
+ ENTER_PRE_SNAPSHOT = 4
13
+ ENTER_POST_SNAPSHOT = 8
14
+ EXIT = 16
15
+ BATCHED = 32
16
+ CLUSTERED = 64 # Experimental: Clustered functions
17
17
 
18
18
  @staticmethod
19
19
  def all() -> int:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: modal
3
- Version: 0.73.17
3
+ Version: 0.73.18
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=qahIuJvaMmWG85N5vNS1yuAQ9XZoo1ftzfatkos_q7I,29553
6
- modal/_functions.py,sha256=Yv8hutin0R_0ZRvUZm8kcjVMf4CNAckgMSDpbLSUl0E,71593
5
+ modal/_container_entrypoint.py,sha256=4z24Tait5ffMOMW4Uqwr4PQKh1eMemjI5CID3L5bvIQ,28588
6
+ modal/_functions.py,sha256=EzTHyRmOFZ75gCuyAIYJDt5EmVW-YoHGLpFzU50WclE,71424
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
@@ -12,7 +12,7 @@ modal/_proxy_tunnel.py,sha256=gnKyCfmVB7x2d1A6c-JDysNIP3kEFxmXzhcXhPrzPn0,1906
12
12
  modal/_pty.py,sha256=JZfPDDpzqICZqtyPI_oMJf_9w-p_lLNuzHhwhodUXio,1329
13
13
  modal/_resolver.py,sha256=D9IAdZKNqRPwgPDaB-XMKGtO8G0GwtBzG6xdgiXKdCk,6945
14
14
  modal/_resources.py,sha256=5qmcirXUI8dSH926nwkUaeX9H25mqYu9mXD_KuT79-o,1733
15
- modal/_serialization.py,sha256=x0uArKNXg89SfmKMUaLup_moHodax9weZItkChKeQ64,18745
15
+ modal/_serialization.py,sha256=NYSjM9FnbLXULuzpboVvPcFFHRyh3hn_AcSFXQCGPYc,19741
16
16
  modal/_traceback.py,sha256=IZQzB3fVlUfMHOSyKUgw0H6qv4yHnpyq-XVCNZKfUdA,5023
17
17
  modal/_tunnel.py,sha256=zTBxBiuH1O22tS1OliAJdIsSmaZS8PlnifS_6S5z-mk,6320
18
18
  modal/_tunnel.pyi,sha256=JmmDYAy9F1FpgJ_hWx0xkom2nTOFQjn4mTPYlU3PFo4,1245
@@ -21,10 +21,10 @@ 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=GERfkfH3ad1hI1hGHl-jVSmCFKTUse1qlsJvy6O_cc0,7593
24
+ modal/client.pyi,sha256=cNwqALG4kBZVaMLuwJOhuLJqbm-6ZseQgYH9GHpSYto,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
- modal/cls.py,sha256=kNnZrBYVXOhgEXU0rDWk2Hr-bQRrsZkMKDgC-TD_6Bs,31063
27
+ modal/cls.py,sha256=agxclIXZbzBbgcI5PPVD7IfOiHzv-B82xaaXtw9cpv8,31126
28
28
  modal/cls.pyi,sha256=gb6QNwfX3HSJfcZXPY36N9ywF7aBJTwwtoARnf3G1HQ,8877
29
29
  modal/config.py,sha256=XT1W4Y9PVkbYMAXjJRshvQEPDhZmnfW_ZRMwl8XKoqA,11149
30
30
  modal/container_process.py,sha256=WTqLn01dJPVkPpwR_0w_JH96ceN5mV4TGtiu1ZR2RRA,6108
@@ -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=emiPRWAgr10f5twtUhC3kBZQZ91fZ74VNdePy7YAspE,7267
45
45
  modal/image.py,sha256=ekE2693foy30Xi1LM3swKZPW6HuaACj-OBvfspVSyIE,91509
46
46
  modal/image.pyi,sha256=kdJzy1eaxNPZeCpE0TMYYLhJ6UWmkfRDeb_vzngJUoQ,26462
@@ -55,8 +55,8 @@ modal/object.pyi,sha256=kyJkRQcVv3ct7zSAxvvXcuhBVeH914v80uSlqeS7cA4,5632
55
55
  modal/output.py,sha256=N0xf4qeudEaYrslzdAl35VKV8rapstgIM2e9wO8_iy0,1967
56
56
  modal/parallel_map.py,sha256=POBTyiWabe2e4qBNlsjjksiu1AAPEsNqI-mM8cgNFco,16042
57
57
  modal/parallel_map.pyi,sha256=-YKY_bVuQv8B4gtFrHnXtuNV0_JpmU9vqMJzR7beeCU,2524
58
- modal/partial_function.py,sha256=0KRvTMTVPycaxX1iq-QbH21Wnf7Gzu2JHp6FYp0OdLs,28743
59
- modal/partial_function.pyi,sha256=pgKMv28XYy8-y-Li1ciX7aqud3ICCB0-nVr9Gh2G-ZA,9930
58
+ modal/partial_function.py,sha256=vlZz1eVDoTWZWkyyG5peujEi_jvQ07U0_qmRflh0Dt8,28708
59
+ modal/partial_function.pyi,sha256=UI0YJpp8sQw8vWA-S_G3qT6HVKfeiUN9kmk4H1YofkI,9895
60
60
  modal/proxy.py,sha256=NrOevrWxG3G7-zlyRzG6BcIvop7AWLeyahZxitbBaOk,1418
61
61
  modal/proxy.pyi,sha256=1OEKIVUyC-xb7fHMzngakQso0nTsK60TVhXtlcMj6Wk,390
62
62
  modal/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -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=YQ92GzLK4h10xkDU7zCwSroTo_UYCQkFnHwhKT3BilI,149
175
- modal-0.73.17.dist-info/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
176
- modal-0.73.17.dist-info/METADATA,sha256=zCNB6cid3cY0BQByHeKAC1FjbLJlqM9pfog8-JaU94k,2330
177
- modal-0.73.17.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
178
- modal-0.73.17.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
179
- modal-0.73.17.dist-info/top_level.txt,sha256=1nvYbOSIKcmU50fNrpnQnrrOpj269ei3LzgB6j9xGqg,64
180
- modal-0.73.17.dist-info/RECORD,,
174
+ modal_version/_version_generated.py,sha256=es_zQAYbXwNk2rQzYcTt5Fz_sg-TMBpv3shgnxer39E,149
175
+ modal-0.73.18.dist-info/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
176
+ modal-0.73.18.dist-info/METADATA,sha256=Og9a1J6CGa1pKBSDkusnllp6lUNNu2iH_lwoU9_UFdA,2330
177
+ modal-0.73.18.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
178
+ modal-0.73.18.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
179
+ modal-0.73.18.dist-info/top_level.txt,sha256=1nvYbOSIKcmU50fNrpnQnrrOpj269ei3LzgB6j9xGqg,64
180
+ modal-0.73.18.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 = 17 # git: 6c13e4c
4
+ build_number = 18 # git: 9e5aecd