modal 1.1.5.dev44__py3-none-any.whl → 1.1.5.dev45__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.

Potentially problematic release.


This version of modal might be problematic. Click here for more details.

@@ -29,7 +29,7 @@ class FinalizedFunction:
29
29
  callable: Callable[..., Any]
30
30
  is_async: bool
31
31
  is_generator: bool
32
- data_format: int # api_pb2.DataFormat
32
+ supported_output_formats: Sequence["api_pb2.DataFormat.ValueType"]
33
33
  lifespan_manager: Optional["LifespanManager"] = None
34
34
 
35
35
 
@@ -108,6 +108,7 @@ class ImportedFunction(Service):
108
108
  is_generator = fun_def.function_type == api_pb2.Function.FUNCTION_TYPE_GENERATOR
109
109
 
110
110
  webhook_config = fun_def.webhook_config
111
+
111
112
  if not webhook_config.type:
112
113
  # for non-webhooks, the runnable is straight forward:
113
114
  return {
@@ -115,7 +116,10 @@ class ImportedFunction(Service):
115
116
  callable=self._user_defined_callable,
116
117
  is_async=is_async,
117
118
  is_generator=is_generator,
118
- data_format=api_pb2.DATA_FORMAT_PICKLE,
119
+ supported_output_formats=fun_def.supported_output_formats
120
+ # FIXME (elias): the following `or [api_pb2.DATA_FORMAT_PICKLE, api_pb2.DATA_FORMAT_CBOR]` is only
121
+ # needed for tests
122
+ or [api_pb2.DATA_FORMAT_PICKLE, api_pb2.DATA_FORMAT_CBOR],
119
123
  )
120
124
  }
121
125
 
@@ -129,7 +133,8 @@ class ImportedFunction(Service):
129
133
  lifespan_manager=lifespan_manager,
130
134
  is_async=True,
131
135
  is_generator=True,
132
- data_format=api_pb2.DATA_FORMAT_ASGI,
136
+ # FIXME (elias): the following `or [api_pb2.DATA_FORMAT_ASGI]` is only needed for tests
137
+ supported_output_formats=fun_def.supported_output_formats or [api_pb2.DATA_FORMAT_ASGI],
133
138
  )
134
139
  }
135
140
 
@@ -154,6 +159,7 @@ class ImportedClass(Service):
154
159
  # Use the function definition for whether this is a generator (overriden by webhooks)
155
160
  is_generator = _partial.params.is_generator
156
161
  webhook_config = _partial.params.webhook_config
162
+ method_def = fun_def.method_definitions[method_name]
157
163
 
158
164
  bound_func = user_func.__get__(self.user_cls_instance)
159
165
 
@@ -163,7 +169,10 @@ class ImportedClass(Service):
163
169
  callable=bound_func,
164
170
  is_async=is_async,
165
171
  is_generator=bool(is_generator),
166
- data_format=api_pb2.DATA_FORMAT_PICKLE,
172
+ # FIXME (elias): the following `or [api_pb2.DATA_FORMAT_PICKLE, api_pb2.DATA_FORMAT_CBOR]` is only
173
+ # needed for tests
174
+ supported_output_formats=method_def.supported_output_formats
175
+ or [api_pb2.DATA_FORMAT_PICKLE, api_pb2.DATA_FORMAT_CBOR],
167
176
  )
168
177
  else:
169
178
  web_callable, lifespan_manager = construct_webhook_callable(
@@ -174,7 +183,8 @@ class ImportedClass(Service):
174
183
  lifespan_manager=lifespan_manager,
175
184
  is_async=True,
176
185
  is_generator=True,
177
- data_format=api_pb2.DATA_FORMAT_ASGI,
186
+ # FIXME (elias): the following `or [api_pb2.DATA_FORMAT_ASGI]` is only needed for tests
187
+ supported_output_formats=method_def.supported_output_formats or [api_pb2.DATA_FORMAT_ASGI],
178
188
  )
179
189
  finalized_functions[method_name] = finalized_function
180
190
  return finalized_functions
modal/_serialization.py CHANGED
@@ -6,6 +6,14 @@ import typing
6
6
  from inspect import Parameter
7
7
  from typing import Any
8
8
 
9
+ from modal._traceback import extract_traceback
10
+ from modal.config import config
11
+
12
+ try:
13
+ import cbor2 # type: ignore
14
+ except ImportError: # pragma: no cover - optional dependency
15
+ cbor2 = None
16
+
9
17
  import google.protobuf.message
10
18
 
11
19
  from modal._utils.async_utils import synchronizer
@@ -15,7 +23,7 @@ from ._object import _Object
15
23
  from ._type_manager import parameter_serde_registry, schema_registry
16
24
  from ._vendor import cloudpickle
17
25
  from .config import logger
18
- from .exception import DeserializationError, ExecutionError, InvalidError
26
+ from .exception import DeserializationError, ExecutionError, InvalidError, SerializationError
19
27
  from .object import Object
20
28
 
21
29
  if typing.TYPE_CHECKING:
@@ -346,6 +354,12 @@ def _deserialize_asgi(asgi: api_pb2.Asgi) -> Any:
346
354
  return None
347
355
 
348
356
 
357
+ def get_preferred_payload_format() -> "api_pb2.DataFormat.ValueType":
358
+ payload_format = (config.get("payload_format") or "pickle").lower()
359
+ data_format = api_pb2.DATA_FORMAT_CBOR if payload_format == "cbor" else api_pb2.DATA_FORMAT_PICKLE
360
+ return data_format
361
+
362
+
349
363
  def serialize_data_format(obj: Any, data_format: int) -> bytes:
350
364
  """Similar to serialize(), but supports other data formats."""
351
365
  if data_format == api_pb2.DATA_FORMAT_PICKLE:
@@ -355,6 +369,21 @@ def serialize_data_format(obj: Any, data_format: int) -> bytes:
355
369
  elif data_format == api_pb2.DATA_FORMAT_GENERATOR_DONE:
356
370
  assert isinstance(obj, api_pb2.GeneratorDone)
357
371
  return obj.SerializeToString(deterministic=True)
372
+ elif data_format == api_pb2.DATA_FORMAT_CBOR:
373
+ if cbor2 is None:
374
+ raise InvalidError("CBOR support requires the 'cbor2' package to be installed.")
375
+ try:
376
+ return cbor2.dumps(obj)
377
+ except cbor2.CBOREncodeTypeError:
378
+ try:
379
+ typename = f"{type(obj).__module__}.{type(obj).__name__}"
380
+ except Exception:
381
+ typename = str(type(obj))
382
+ raise SerializationError(
383
+ # TODO (elias): add documentation link for more information on this
384
+ f"Can not serialize type {typename} as cbor. If you need to use a custom data type, "
385
+ "try to serialize it yourself e.g. by using pickle.dumps(my_data)"
386
+ )
358
387
  else:
359
388
  raise InvalidError(f"Unknown data format {data_format!r}")
360
389
 
@@ -366,6 +395,10 @@ def deserialize_data_format(s: bytes, data_format: int, client) -> Any:
366
395
  return _deserialize_asgi(api_pb2.Asgi.FromString(s))
367
396
  elif data_format == api_pb2.DATA_FORMAT_GENERATOR_DONE:
368
397
  return api_pb2.GeneratorDone.FromString(s)
398
+ elif data_format == api_pb2.DATA_FORMAT_CBOR:
399
+ if cbor2 is None:
400
+ raise InvalidError("CBOR support requires the 'cbor2' package to be installed.")
401
+ return cbor2.loads(s)
369
402
  else:
370
403
  raise InvalidError(f"Unknown data format {data_format!r}")
371
404
 
@@ -579,3 +612,26 @@ def get_callable_schema(
579
612
  arguments=arguments,
580
613
  return_type=return_type_proto,
581
614
  )
615
+
616
+
617
+ def pickle_exception(exc: BaseException) -> bytes:
618
+ try:
619
+ return serialize(exc)
620
+ except Exception as serialization_exc:
621
+ # We can't always serialize exceptions.
622
+ err = f"Failed to serialize exception {exc} of type {type(exc)}: {serialization_exc}"
623
+ logger.info(err)
624
+ return serialize(SerializationError(err))
625
+
626
+
627
+ def pickle_traceback(exc: BaseException, task_id: str) -> tuple[bytes, bytes]:
628
+ serialized_tb, tb_line_cache = b"", b""
629
+
630
+ try:
631
+ tb_dict, line_cache = extract_traceback(exc, task_id)
632
+ serialized_tb = serialize(tb_dict)
633
+ tb_line_cache = serialize(line_cache)
634
+ except Exception:
635
+ logger.info("Failed to serialize exception traceback.")
636
+
637
+ return serialized_tb, tb_line_cache
@@ -300,6 +300,10 @@ async def blob_upload(payload: bytes, stub: ModalClientModal) -> str:
300
300
  return blob_id
301
301
 
302
302
 
303
+ async def format_blob_data(data: bytes, api_stub: ModalClientModal) -> dict[str, Any]:
304
+ return {"data_blob_id": await blob_upload(data, api_stub)} if len(data) > MAX_OBJECT_SIZE_BYTES else {"data": data}
305
+
306
+
303
307
  async def blob_upload_file(
304
308
  file_obj: BinaryIO,
305
309
  stub: ModalClientModal,
@@ -2,6 +2,7 @@
2
2
  import asyncio
3
3
  import inspect
4
4
  import os
5
+ import typing
5
6
  from collections.abc import AsyncGenerator
6
7
  from enum import Enum
7
8
  from pathlib import Path, PurePosixPath
@@ -17,7 +18,9 @@ from modal_proto.modal_api_grpc import ModalClientModal
17
18
  from .._serialization import (
18
19
  deserialize,
19
20
  deserialize_data_format,
21
+ get_preferred_payload_format,
20
22
  serialize,
23
+ serialize_data_format as _serialize_data_format,
21
24
  signature_to_parameter_specs,
22
25
  )
23
26
  from .._traceback import append_modal_tb
@@ -38,6 +41,9 @@ from .blob_utils import (
38
41
  )
39
42
  from .grpc_utils import RETRYABLE_GRPC_STATUS_CODES
40
43
 
44
+ if typing.TYPE_CHECKING:
45
+ import modal._functions
46
+
41
47
 
42
48
  class FunctionInfoType(Enum):
43
49
  PACKAGE = "package"
@@ -486,7 +492,7 @@ async def _process_result(result: api_pb2.GenericResult, data_format: int, stub,
486
492
  elif result.status == api_pb2.GenericResult.GENERIC_STATUS_INTERNAL_FAILURE:
487
493
  raise InternalFailure(result.exception)
488
494
  elif result.status != api_pb2.GenericResult.GENERIC_STATUS_SUCCESS:
489
- if data:
495
+ if data and data_format == api_pb2.DATA_FORMAT_PICKLE:
490
496
  try:
491
497
  exc = deserialize(data, client)
492
498
  except DeserializationError as deser_exc:
@@ -549,27 +555,35 @@ async def _create_input(
549
555
  kwargs,
550
556
  stub: ModalClientModal,
551
557
  *,
552
- max_object_size_bytes: int,
558
+ function: "modal._functions._Function",
553
559
  idx: Optional[int] = None,
554
- method_name: Optional[str] = None,
555
560
  function_call_invocation_type: Optional["api_pb2.FunctionCallInvocationType.ValueType"] = None,
556
561
  ) -> api_pb2.FunctionPutInputsItem:
557
562
  """Serialize function arguments and create a FunctionInput protobuf,
558
563
  uploading to blob storage if needed.
559
564
  """
565
+ method_name = function._use_method_name
566
+ max_object_size_bytes = function._max_object_size_bytes
567
+
560
568
  if idx is None:
561
569
  idx = 0
562
- if method_name is None:
563
- method_name = "" # proto compatible
564
570
 
565
- args_serialized = serialize((args, kwargs))
571
+ data_format = get_preferred_payload_format()
572
+ if not function._metadata:
573
+ raise ExecutionError("Attempted to call function that has not been hydrated with metadata")
574
+
575
+ supported_input_formats = function._metadata.supported_input_formats or [api_pb2.DATA_FORMAT_PICKLE]
576
+ if data_format not in supported_input_formats:
577
+ data_format = supported_input_formats[0]
578
+
579
+ args_serialized = _serialize_data_format((args, kwargs), data_format)
566
580
 
567
581
  if should_upload(len(args_serialized), max_object_size_bytes, function_call_invocation_type):
568
582
  args_blob_id, r2_failed, r2_throughput_bytes_s = await blob_upload_with_r2_failure_info(args_serialized, stub)
569
583
  return api_pb2.FunctionPutInputsItem(
570
584
  input=api_pb2.FunctionInput(
571
585
  args_blob_id=args_blob_id,
572
- data_format=api_pb2.DATA_FORMAT_PICKLE,
586
+ data_format=data_format,
573
587
  method_name=method_name,
574
588
  ),
575
589
  idx=idx,
@@ -580,7 +594,7 @@ async def _create_input(
580
594
  return api_pb2.FunctionPutInputsItem(
581
595
  input=api_pb2.FunctionInput(
582
596
  args=args_serialized,
583
- data_format=api_pb2.DATA_FORMAT_PICKLE,
597
+ data_format=data_format,
584
598
  method_name=method_name,
585
599
  ),
586
600
  idx=idx,
modal/app.py CHANGED
@@ -667,6 +667,7 @@ class _App:
667
667
  ] = None, # Experimental controls over fine-grained scheduling (alpha).
668
668
  _experimental_proxy_ip: Optional[str] = None, # IP address of proxy
669
669
  _experimental_custom_scaling_factor: Optional[float] = None, # Custom scaling factor
670
+ _experimental_restrict_output: bool = False, # Don't use pickle for return values
670
671
  # Parameters below here are deprecated. Please update your code as suggested
671
672
  keep_warm: Optional[int] = None, # Replaced with `min_containers`
672
673
  concurrency_limit: Optional[int] = None, # Replaced with `max_containers`
@@ -835,6 +836,7 @@ class _App:
835
836
  include_source=include_source if include_source is not None else self._include_source_default,
836
837
  experimental_options={k: str(v) for k, v in (experimental_options or {}).items()},
837
838
  _experimental_proxy_ip=_experimental_proxy_ip,
839
+ restrict_output=_experimental_restrict_output,
838
840
  )
839
841
 
840
842
  self._add_function(function, webhook_config is not None)
@@ -895,6 +897,7 @@ class _App:
895
897
  ] = None, # Experimental controls over fine-grained scheduling (alpha).
896
898
  _experimental_proxy_ip: Optional[str] = None, # IP address of proxy
897
899
  _experimental_custom_scaling_factor: Optional[float] = None, # Custom scaling factor
900
+ _experimental_restrict_output: bool = False, # Don't use pickle for return values
898
901
  # Parameters below here are deprecated. Please update your code as suggested
899
902
  keep_warm: Optional[int] = None, # Replaced with `min_containers`
900
903
  concurrency_limit: Optional[int] = None, # Replaced with `max_containers`
@@ -1028,6 +1031,7 @@ class _App:
1028
1031
  experimental_options={k: str(v) for k, v in (experimental_options or {}).items()},
1029
1032
  _experimental_proxy_ip=_experimental_proxy_ip,
1030
1033
  _experimental_custom_scaling_factor=_experimental_custom_scaling_factor,
1034
+ restrict_output=_experimental_restrict_output,
1031
1035
  )
1032
1036
 
1033
1037
  self._add_function(cls_func, is_web_endpoint=False)
modal/app.pyi CHANGED
@@ -427,6 +427,7 @@ class _App:
427
427
  _experimental_scheduler_placement: typing.Optional[modal.scheduler_placement.SchedulerPlacement] = None,
428
428
  _experimental_proxy_ip: typing.Optional[str] = None,
429
429
  _experimental_custom_scaling_factor: typing.Optional[float] = None,
430
+ _experimental_restrict_output: bool = False,
430
431
  keep_warm: typing.Optional[int] = None,
431
432
  concurrency_limit: typing.Optional[int] = None,
432
433
  container_idle_timeout: typing.Optional[int] = None,
@@ -480,6 +481,7 @@ class _App:
480
481
  _experimental_scheduler_placement: typing.Optional[modal.scheduler_placement.SchedulerPlacement] = None,
481
482
  _experimental_proxy_ip: typing.Optional[str] = None,
482
483
  _experimental_custom_scaling_factor: typing.Optional[float] = None,
484
+ _experimental_restrict_output: bool = False,
483
485
  keep_warm: typing.Optional[int] = None,
484
486
  concurrency_limit: typing.Optional[int] = None,
485
487
  container_idle_timeout: typing.Optional[int] = None,
@@ -1034,6 +1036,7 @@ class App:
1034
1036
  _experimental_scheduler_placement: typing.Optional[modal.scheduler_placement.SchedulerPlacement] = None,
1035
1037
  _experimental_proxy_ip: typing.Optional[str] = None,
1036
1038
  _experimental_custom_scaling_factor: typing.Optional[float] = None,
1039
+ _experimental_restrict_output: bool = False,
1037
1040
  keep_warm: typing.Optional[int] = None,
1038
1041
  concurrency_limit: typing.Optional[int] = None,
1039
1042
  container_idle_timeout: typing.Optional[int] = None,
@@ -1087,6 +1090,7 @@ class App:
1087
1090
  _experimental_scheduler_placement: typing.Optional[modal.scheduler_placement.SchedulerPlacement] = None,
1088
1091
  _experimental_proxy_ip: typing.Optional[str] = None,
1089
1092
  _experimental_custom_scaling_factor: typing.Optional[float] = None,
1093
+ _experimental_restrict_output: bool = False,
1090
1094
  keep_warm: typing.Optional[int] = None,
1091
1095
  concurrency_limit: typing.Optional[int] = None,
1092
1096
  container_idle_timeout: typing.Optional[int] = None,
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.5.dev44",
36
+ version: str = "1.1.5.dev45",
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.5.dev44",
167
+ version: str = "1.1.5.dev45",
168
168
  ):
169
169
  """mdmd:hidden
170
170
  The Modal client object is not intended to be instantiated directly by users.
modal/config.py CHANGED
@@ -239,6 +239,11 @@ _SETTINGS = {
239
239
  "snapshot_debug": _Setting(False, transform=_to_boolean),
240
240
  "cuda_checkpoint_path": _Setting("/__modal/.bin/cuda-checkpoint"), # Used for snapshotting GPU memory.
241
241
  "build_validation": _Setting("error", transform=_check_value(["error", "warn", "ignore"])),
242
+ # Payload format for function inputs/outputs: 'pickle' (default) or 'cbor'
243
+ "payload_format": _Setting(
244
+ "pickle",
245
+ transform=lambda s: _check_value(["pickle", "cbor"])(s.lower()),
246
+ ),
242
247
  }
243
248
 
244
249
 
modal/functions.pyi CHANGED
@@ -111,6 +111,7 @@ class Function(
111
111
  experimental_options: typing.Optional[dict[str, str]] = None,
112
112
  _experimental_proxy_ip: typing.Optional[str] = None,
113
113
  _experimental_custom_scaling_factor: typing.Optional[float] = None,
114
+ restrict_output: bool = False,
114
115
  ) -> Function:
115
116
  """mdmd:hidden
116
117
 
modal/image.py CHANGED
@@ -25,11 +25,12 @@ from google.protobuf.message import Message
25
25
  from grpclib.exceptions import GRPCError, StreamTerminatedError
26
26
  from typing_extensions import Self
27
27
 
28
+ from modal._serialization import serialize_data_format
28
29
  from modal_proto import api_pb2
29
30
 
30
31
  from ._object import _Object, live_method_gen
31
32
  from ._resolver import Resolver
32
- from ._serialization import serialize
33
+ from ._serialization import get_preferred_payload_format, serialize
33
34
  from ._utils.async_utils import synchronize_api
34
35
  from ._utils.blob_utils import MAX_OBJECT_SIZE_BYTES
35
36
  from ._utils.deprecation import deprecation_warning
@@ -2318,13 +2319,19 @@ class _Image(_Object, type_prefix="im"):
2318
2319
  include_source=include_source,
2319
2320
  )
2320
2321
  if len(args) + len(kwargs) > 0:
2321
- args_serialized = serialize((args, kwargs))
2322
+ data_format = get_preferred_payload_format()
2323
+ args_serialized = serialize_data_format((args, kwargs), data_format)
2324
+
2322
2325
  if len(args_serialized) > MAX_OBJECT_SIZE_BYTES:
2323
2326
  raise InvalidError(
2324
2327
  f"Arguments to `run_function` are too large ({len(args_serialized)} bytes). "
2325
2328
  f"Maximum size is {MAX_OBJECT_SIZE_BYTES} bytes."
2326
2329
  )
2327
- build_function_input = api_pb2.FunctionInput(args=args_serialized, data_format=api_pb2.DATA_FORMAT_PICKLE)
2330
+
2331
+ build_function_input = api_pb2.FunctionInput(
2332
+ args=args_serialized,
2333
+ data_format=data_format,
2334
+ )
2328
2335
  else:
2329
2336
  build_function_input = None
2330
2337
  return _Image._from_args(
modal/parallel_map.py CHANGED
@@ -128,9 +128,8 @@ class InputPreprocessor:
128
128
  args,
129
129
  kwargs,
130
130
  self.client.stub,
131
- max_object_size_bytes=self.function._max_object_size_bytes,
132
131
  idx=idx,
133
- method_name=self.function._use_method_name,
132
+ function=self.function,
134
133
  )
135
134
 
136
135
  return create_input
@@ -728,9 +727,8 @@ async def _map_invocation_inputplane(
728
727
  args,
729
728
  kwargs,
730
729
  client.stub,
731
- max_object_size_bytes=function._max_object_size_bytes,
732
730
  idx=idx,
733
- method_name=function._use_method_name,
731
+ function=function,
734
732
  )
735
733
  return api_pb2.MapStartOrContinueItem(input=put_item)
736
734
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.1.5.dev44
3
+ Version: 1.1.5.dev45
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License: Apache-2.0
@@ -17,6 +17,7 @@ Requires-Python: >=3.9
17
17
  Description-Content-Type: text/markdown
18
18
  License-File: LICENSE
19
19
  Requires-Dist: aiohttp
20
+ Requires-Dist: cbor2
20
21
  Requires-Dist: certifi
21
22
  Requires-Dist: click~=8.1
22
23
  Requires-Dist: grpclib<0.4.9,>=0.4.7
@@ -2,8 +2,8 @@ modal/__init__.py,sha256=WMaRW-2IJRGA9ioNAaBhJYuyLvu-GS01L8wQD90fKBs,2682
2
2
  modal/__main__.py,sha256=45H-GtwzaDfN-1nP4_HYvzN3s7AG_HXR4-ynrsjO_OI,2803
3
3
  modal/_clustered_functions.py,sha256=Sy4Sf_17EO8OL-FUe8LYcm4hrqLyQFCssNhr3p0SroU,3013
4
4
  modal/_clustered_functions.pyi,sha256=JmYwAGOLEnD5AF-gYF9O5tu-SgGjeoJz-X1j48b1Ijg,1157
5
- modal/_container_entrypoint.py,sha256=fLluT_sU34vGPCTG1Q58VI1RvxF5n7vQzCVCsL-MMk8,29033
6
- modal/_functions.py,sha256=e2HUGJ9Cd1rZnbyzL3DpsAsb_Lnwzs2ud_Khyh-nseE,91399
5
+ modal/_container_entrypoint.py,sha256=B_fIKKjWposiNsYOePifX7S6cR9hf5LRPhDfVums5O8,27867
6
+ modal/_functions.py,sha256=6e4rFdl8thTnRuhUOj_4ehOzC1wdvJHhYSoIwB0LXhU,91783
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
@@ -12,22 +12,22 @@ modal/_partial_function.py,sha256=Yqk97hLS6vi8nWWVpzS5TSWbndWMdCtkhccdnyDJgBk,37
12
12
  modal/_pty.py,sha256=E58MQ8d5-wkbMatRKpQR-G9FdbCRcZGiZxOpGy__VuY,1481
13
13
  modal/_resolver.py,sha256=2RWvm34cNSnbv1v7izJMNZgfvpLDD6LzaBlr0lIrLnY,7364
14
14
  modal/_resources.py,sha256=NMAp0GCLutiZI4GuKSIVnRHVlstoD3hNGUabjTUtzf4,1794
15
- modal/_serialization.py,sha256=wt09fOwo-E9ATlOG91O9RXCTPRNtsm97v4Unk8Bzd-8,24145
15
+ modal/_serialization.py,sha256=_3-Z9jSoleDnv2HghH2kfo0m_WG8Iajs1wop1Iqnam8,26341
16
16
  modal/_traceback.py,sha256=muKP7RbAXq74UGwkaVIdOxDdfDug0UcDKr9fe4LL3m8,6503
17
17
  modal/_tunnel.py,sha256=zTBxBiuH1O22tS1OliAJdIsSmaZS8PlnifS_6S5z-mk,6320
18
18
  modal/_tunnel.pyi,sha256=rvC7USR2BcKkbZIeCJXwf7-UfGE-LPLjKsGNiK7Lxa4,13366
19
19
  modal/_type_manager.py,sha256=DWjgmjYJuOagw2erin506UUbG2H5UzZCFEekS-7hmfA,9087
20
20
  modal/_watcher.py,sha256=K6LYnlmSGQB4tWWI9JADv-tvSvQ1j522FwT71B51CX8,3584
21
- modal/app.py,sha256=OBFaL-8KVMtBMEmspHA76LvblPdnSgdoGioLkQBjhdQ,48851
22
- modal/app.pyi,sha256=Cqk3pOeEEroCLejj3yJ3XHDqt0rMzeSA295gMKEx6Ww,43955
21
+ modal/app.py,sha256=Escm3cNiy0cXnVazO85BQgBItGeNXSfxqNEFiqcxqXk,49159
22
+ modal/app.pyi,sha256=KzBPGM8nJc-y_79jNYlSXb6iseG0Sn0Mk73Lq5zTlfA,44167
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=IOo9lNqInnVAPZe6hY583DiFCUXP-ANjdfLFv-Zei-I,15831
25
+ modal/client.pyi,sha256=mlveYEQHlDuHI5Sx--YWXfPuk_79R_yYiOtTPGrFqbE,15831
26
26
  modal/cloud_bucket_mount.py,sha256=I2GRXYhOWLIz2kJZjXu75jAm9EJkBNcutGc6jR2ReUw,5928
27
27
  modal/cloud_bucket_mount.pyi,sha256=VuUOipMIHqFXMkD-3g2bsoqpSxV5qswlFHDOqPQzYAo,7405
28
28
  modal/cls.py,sha256=R1uLQbdqWRRjvxs0I57a4hZZELZkBVCxOKxvKryU5_s,41639
29
29
  modal/cls.pyi,sha256=PRvC9lWIBL-L4cMc9cIt8I_ZDXI7oFttitKaFWWwhUk,29709
30
- modal/config.py,sha256=hpcfT03tdB-G0exZ4HjYDHwDtA8XcnliiyZzCcTbr8o,12124
30
+ modal/config.py,sha256=OLxJU1K7ijiV_65g700QcHX8hIPH-dgzuybyQAOf6cg,12333
31
31
  modal/container_process.py,sha256=Mutkl7sg_WR5zP4oJiWSC-3UdYRqp0zdKi1shZbi-bk,6996
32
32
  modal/container_process.pyi,sha256=9m-st3hCUlNN1GOTctfPPvIvoLtEl7FbuGWwif5-7YU,6037
33
33
  modal/dict.py,sha256=PGtZWy1F72qkoYu6_6chXLFQczobZwZyCxYle0vEd-o,22988
@@ -39,9 +39,9 @@ modal/file_io.py,sha256=OSKr77TujcXGJW1iikzYiHckLSmv07QBgBHcxxYEkoI,21456
39
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=_xKitEUTNQStdZVtYBgWidtyHHsnjXUYgbirM0eMDyM,39558
42
+ modal/functions.pyi,sha256=FU1F_75_-Y-YEWo6UNxvmuQ8P3T8TNgpqEqhgED4dhc,39597
43
43
  modal/gpu.py,sha256=Fe5ORvVPDIstSq1xjmM6OoNgLYFWvogP9r5BgmD3hYg,6769
44
- modal/image.py,sha256=ioYIpKq4Fi1ojqdIyochyoRU1_Ncto_BSYLKzY88zuw,107883
44
+ modal/image.py,sha256=pCiIeDt-YDpzBZ7_uqPcuizRniZYG34Z_NDMCsIIjas,108084
45
45
  modal/image.pyi,sha256=ZNp48mVPzcQ6XNvxin1iO5XrZ89vfEZvU1Bi-V57jq0,76835
46
46
  modal/io_streams.py,sha256=hZOVc5beOAm8S_VQQmmKUbk_BJ9OltN83RY0yMPqUDo,16545
47
47
  modal/io_streams.pyi,sha256=aOun_jUFKHSJyUY6-7gKvNoxzcULsa8_hxdtEO7v-gk,13980
@@ -52,7 +52,7 @@ modal/network_file_system.pyi,sha256=Zg5Wg2c-EGOn2xTo2zgPbmtdyt51eda5E63UefI9yes
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=I2GADci-u1G_r7CxFzL11C0c3P4Tf_Jb3f_XCp4p_WI,69293
55
+ modal/parallel_map.py,sha256=BkAQER2p3uus2VaODO6r_NhYDGtrh6dBF4AK2AhfIGI,69110
56
56
  modal/parallel_map.pyi,sha256=NZrtfZljig59hcMKU7Cz8lYZZFOiwK9l7oWrBtX6Oy8,15838
57
57
  modal/partial_function.py,sha256=aIdlGfTjjgqY6Fpr-biCjvRU9W542_S5N2xkNN_rYGM,1127
58
58
  modal/partial_function.pyi,sha256=lqqOzZ9-QvHTDWKQ_oAYYOvsXgTOBKhO9u-RI98JbUk,13986
@@ -82,22 +82,22 @@ modal/volume.py,sha256=bPC8632-LyeLOjJu2fKOFyod0QG7Hd5bb-UIJ5syCjo,53303
82
82
  modal/volume.pyi,sha256=5VppIgoqoJqpivESYt5_oWgVTL__zlmpNZkOPk43JF8,54443
83
83
  modal/_runtime/__init__.py,sha256=MIEP8jhXUeGq_eCjYFcqN5b1bxBM4fdk0VESpjWR0fc,28
84
84
  modal/_runtime/asgi.py,sha256=AOcduIlijmlxhXVWo7AIUhigo-bqm6nDkHj4Q4JLy6o,22607
85
- modal/_runtime/container_io_manager.py,sha256=thGJADZe7KW_2XlOn4oG7pBb8wQ3eKs1iATA_2U7jvU,45800
86
- modal/_runtime/container_io_manager.pyi,sha256=pcGX7wUdidc2IO3eWOnsEgl9N8e8HG3yFIItXL6JgJI,23626
85
+ modal/_runtime/container_io_manager.py,sha256=HZJsAC7Vn1a3EXpyJAMuOibsFulHpWlqTE420_jJRWw,51775
86
+ modal/_runtime/container_io_manager.pyi,sha256=GDNLirCcPMRc6gckInYKmGmJZY3LNcgUVXKftt9P9jI,23493
87
87
  modal/_runtime/execution_context.py,sha256=AYrNQRHHXEqX2MwMf8zxelKZnYf25RE_B-NRLWf93n8,3521
88
88
  modal/_runtime/execution_context.pyi,sha256=FVzakehz72ndL-ufe8-EC7TM4IHO_MEBcAdgWuU4W9k,2426
89
89
  modal/_runtime/gpu_memory_snapshot.py,sha256=BWIMKkH-UXTQOJJuXbM15UWCHHSYlJ0XxGlZunKb0Ug,11877
90
90
  modal/_runtime/telemetry.py,sha256=T1RoAGyjBDr1swiM6pPsGRSITm7LI5FDK18oNXxY08U,5163
91
- modal/_runtime/user_code_imports.py,sha256=SSkrluFuOtcM0NIOwqVlcFhAKhkAGjnPKjJj_Ht_nzk,15574
91
+ modal/_runtime/user_code_imports.py,sha256=1MlOgw810aj0MeDvFPvHBIz-aHd7jUX6dwRfIcM3-KE,16498
92
92
  modal/_utils/__init__.py,sha256=waLjl5c6IPDhSsdWAm9Bji4e2PVxamYABKAze6CHVXY,28
93
93
  modal/_utils/app_utils.py,sha256=88BT4TPLWfYAQwKTHcyzNQRHg8n9B-QE2UyJs96iV-0,108
94
94
  modal/_utils/async_utils.py,sha256=7uA4KJV7XRgak5nXZSGRE-RN1h91UOyNwK6v_ilUQMQ,29737
95
95
  modal/_utils/auth_token_manager.py,sha256=i-kfLgDd4BMAw6wouO5aKfNGHo27VAZoVOsbEWqDr2I,5252
96
- modal/_utils/blob_utils.py,sha256=Hb4hobPJpdE7TOUUAhkE3QQSxPVx1w5U9Dkwk7W84jk,22665
96
+ modal/_utils/blob_utils.py,sha256=bmPPHfLy8Kdna8e2xS3lvKwnN5pJUUt_rN39kVIYPFM,22874
97
97
  modal/_utils/bytes_io_segment_payload.py,sha256=vaXPq8b52-x6G2hwE7SrjS58pg_aRm7gV3bn3yjmTzQ,4261
98
98
  modal/_utils/deprecation.py,sha256=-Bgg7jZdcJU8lROy18YyVnQYbM8hue-hVmwJqlWAGH0,5504
99
99
  modal/_utils/docker_utils.py,sha256=h1uETghR40mp_y3fSWuZAfbIASH1HMzuphJHghAL6DU,3722
100
- modal/_utils/function_utils.py,sha256=NWoVg9UgUSS9RSfT9wQUDNcPMmZxjM68-Ch6u4Cp_hk,27481
100
+ modal/_utils/function_utils.py,sha256=6PLmt4U_Kpi-cXvPvIgjDCeYJoFMkf0XzpEJ_0QczdQ,28070
101
101
  modal/_utils/git_utils.py,sha256=qtUU6JAttF55ZxYq51y55OR58B0tDPZsZWK5dJe6W5g,3182
102
102
  modal/_utils/grpc_testing.py,sha256=H1zHqthv19eGPJz2HKXDyWXWGSqO4BRsxah3L5Xaa8A,8619
103
103
  modal/_utils/grpc_utils.py,sha256=1dQgTvdHG9KSfyVTc26HhKjGnIDJpdDEJ0xZARklOrU,10205
@@ -153,7 +153,7 @@ modal/experimental/__init__.py,sha256=fCqzo_f3vcY750vHtd7CtLs5dvdM_C0ZLLGb3zXuK9
153
153
  modal/experimental/flash.py,sha256=7qRAL2Nrwbb60YKobcnpM0zJ8vw4xGJqabLPFgEzMZE,28295
154
154
  modal/experimental/flash.pyi,sha256=R9VV0UDotiY9BRUjacB-xI4qhR3yBymAvEZFRFHztLs,15143
155
155
  modal/experimental/ipython.py,sha256=TrCfmol9LGsRZMeDoeMPx3Hv3BFqQhYnmD_iH0pqdhk,2904
156
- modal-1.1.5.dev44.dist-info/licenses/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
156
+ modal-1.1.5.dev45.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
@@ -182,10 +182,10 @@ modal_proto/sandbox_router_pb2.py,sha256=INd9izYaIYqllESQt4MSv2Rj9Hf5bMjAvtCc9b4
182
182
  modal_proto/sandbox_router_pb2.pyi,sha256=YCK0WnCgRos3-p7t4USQQ7x6WAuM278yeQX2IeU5mLg,13295
183
183
  modal_proto/sandbox_router_pb2_grpc.py,sha256=zonC5flvCwxeZYJPENj1IJo2Mr0J58DpoC1_8IdPYik,8243
184
184
  modal_proto/sandbox_router_pb2_grpc.pyi,sha256=4QgCB9b7_ykvH8YD-hfnogVH9CLyHVDC5QNb03l4_X8,2735
185
- modal_version/__init__.py,sha256=isX0xgSwVTpW1el4-PG6zkykdFDxDNzaHrfggIcX-2k,121
185
+ modal_version/__init__.py,sha256=g-GzSSIDtPtEXTMCPIfvSp4LV6i0AQj8LKX8RM3F__0,121
186
186
  modal_version/__main__.py,sha256=2FO0yYQQwDTh6udt1h-cBnGd1c4ZyHnHSI4BksxzVac,105
187
- modal-1.1.5.dev44.dist-info/METADATA,sha256=s31Bo3Ji-_ftZBHGCfAVQMvoGy7xQ7b5SlQbkS667R4,2460
188
- modal-1.1.5.dev44.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
189
- modal-1.1.5.dev44.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
190
- modal-1.1.5.dev44.dist-info/top_level.txt,sha256=4BWzoKYREKUZ5iyPzZpjqx4G8uB5TWxXPDwibLcVa7k,43
191
- modal-1.1.5.dev44.dist-info/RECORD,,
187
+ modal-1.1.5.dev45.dist-info/METADATA,sha256=i9qwwsFhQgfIZn2Fn2Jbfp8HZpsMyaVm879xMD8pRQQ,2481
188
+ modal-1.1.5.dev45.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
189
+ modal-1.1.5.dev45.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
190
+ modal-1.1.5.dev45.dist-info/top_level.txt,sha256=4BWzoKYREKUZ5iyPzZpjqx4G8uB5TWxXPDwibLcVa7k,43
191
+ modal-1.1.5.dev45.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.5.dev44"
4
+ __version__ = "1.1.5.dev45"