modal 0.74.5__py3-none-any.whl → 0.74.7__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.
@@ -33,7 +33,7 @@ from modal._partial_function import (
33
33
  _find_callables_for_obj,
34
34
  _PartialFunctionFlags,
35
35
  )
36
- from modal._serialization import deserialize_params
36
+ from modal._serialization import deserialize, deserialize_params
37
37
  from modal._utils.async_utils import TaskContext, synchronizer
38
38
  from modal._utils.function_utils import (
39
39
  callable_has_non_self_params,
@@ -394,7 +394,17 @@ def main(container_args: api_pb2.ContainerArguments, client: Client):
394
394
  with container_io_manager.heartbeats(is_snapshotting_function), UserCodeEventLoop() as event_loop:
395
395
  # If this is a serialized function, fetch the definition from the server
396
396
  if function_def.definition_type == api_pb2.Function.DEFINITION_TYPE_SERIALIZED:
397
- ser_usr_cls, ser_fun = container_io_manager.get_serialized_function()
397
+ assert function_def.function_serialized or function_def.class_serialized
398
+
399
+ if function_def.function_serialized:
400
+ ser_fun = deserialize(function_def.function_serialized, _client)
401
+ else:
402
+ ser_fun = None
403
+
404
+ if function_def.class_serialized:
405
+ ser_usr_cls = deserialize(function_def.class_serialized, _client)
406
+ else:
407
+ ser_usr_cls = None
398
408
  else:
399
409
  ser_usr_cls, ser_fun = None, None
400
410
 
modal/_resolver.py CHANGED
@@ -1,6 +1,8 @@
1
1
  # Copyright Modal Labs 2023
2
2
  import asyncio
3
3
  import contextlib
4
+ import os
5
+ import tempfile
4
6
  import typing
5
7
  from asyncio import Future
6
8
  from collections.abc import Hashable
@@ -46,6 +48,7 @@ class Resolver:
46
48
  _app_id: Optional[str]
47
49
  _deduplication_cache: dict[Hashable, Future]
48
50
  _client: _Client
51
+ _build_start: float
49
52
 
50
53
  def __init__(
51
54
  self,
@@ -73,6 +76,11 @@ class Resolver:
73
76
  self._environment_name = environment_name
74
77
  self._deduplication_cache = {}
75
78
 
79
+ with tempfile.TemporaryFile() as temp_file:
80
+ # Use file mtime to track build start time because we will later compare this baseline
81
+ # to the mtime on mounted files, and want those measurements to have the same resolution.
82
+ self._build_start = os.fstat(temp_file.fileno()).st_mtime
83
+
76
84
  @property
77
85
  def app_id(self) -> Optional[str]:
78
86
  return self._app_id
@@ -85,6 +93,10 @@ class Resolver:
85
93
  def environment_name(self):
86
94
  return self._environment_name
87
95
 
96
+ @property
97
+ def build_start(self) -> float:
98
+ return self._build_start
99
+
88
100
  async def preload(self, obj, existing_object_id: Optional[str]):
89
101
  if obj._preload is not None:
90
102
  await obj._preload(obj, self, existing_object_id)
@@ -450,28 +450,6 @@ class _ContainerIOManager:
450
450
 
451
451
  await asyncio.sleep(DYNAMIC_CONCURRENCY_INTERVAL_SECS)
452
452
 
453
- async def get_serialized_function(self) -> tuple[Optional[Any], Optional[Callable[..., Any]]]:
454
- # Fetch the serialized function definition
455
- request = api_pb2.FunctionGetSerializedRequest(function_id=self.function_id)
456
- response = await self._client.stub.FunctionGetSerialized(request)
457
- if response.function_serialized:
458
- fun = self.deserialize(response.function_serialized)
459
- else:
460
- fun = None
461
-
462
- if response.class_serialized:
463
- cls = self.deserialize(response.class_serialized)
464
- else:
465
- cls = None
466
-
467
- return cls, fun
468
-
469
- def serialize(self, obj: Any) -> bytes:
470
- return serialize(obj)
471
-
472
- def deserialize(self, data: bytes) -> Any:
473
- return deserialize(data, self._client)
474
-
475
453
  @synchronizer.no_io_translation
476
454
  def serialize_data_format(self, obj: Any, data_format: int) -> bytes:
477
455
  return serialize_data_format(obj, data_format)
@@ -680,20 +658,20 @@ class _ContainerIOManager:
680
658
 
681
659
  def serialize_exception(self, exc: BaseException) -> bytes:
682
660
  try:
683
- return self.serialize(exc)
661
+ return serialize(exc)
684
662
  except Exception as serialization_exc:
685
663
  # We can't always serialize exceptions.
686
664
  err = f"Failed to serialize exception {exc} of type {type(exc)}: {serialization_exc}"
687
665
  logger.info(err)
688
- return self.serialize(SerializationError(err))
666
+ return serialize(SerializationError(err))
689
667
 
690
668
  def serialize_traceback(self, exc: BaseException) -> tuple[Optional[bytes], Optional[bytes]]:
691
669
  serialized_tb, tb_line_cache = None, None
692
670
 
693
671
  try:
694
672
  tb_dict, line_cache = extract_traceback(exc, self.task_id)
695
- serialized_tb = self.serialize(tb_dict)
696
- tb_line_cache = self.serialize(line_cache)
673
+ serialized_tb = serialize(tb_dict)
674
+ tb_line_cache = serialize(line_cache)
697
675
  except Exception:
698
676
  logger.info("Failed to serialize exception traceback.")
699
677
 
@@ -100,11 +100,6 @@ class _ContainerIOManager:
100
100
  def stop_heartbeat(self): ...
101
101
  def dynamic_concurrency_manager(self) -> typing.AsyncContextManager[None]: ...
102
102
  async def _dynamic_concurrency_loop(self): ...
103
- async def get_serialized_function(
104
- self,
105
- ) -> tuple[typing.Optional[typing.Any], typing.Optional[collections.abc.Callable[..., typing.Any]]]: ...
106
- def serialize(self, obj: typing.Any) -> bytes: ...
107
- def deserialize(self, data: bytes) -> typing.Any: ...
108
103
  def serialize_data_format(self, obj: typing.Any, data_format: int) -> bytes: ...
109
104
  async def format_blob_data(self, data: bytes) -> dict[str, typing.Any]: ...
110
105
  def get_data_in(self, function_call_id: str) -> collections.abc.AsyncIterator[typing.Any]: ...
@@ -234,18 +229,6 @@ class ContainerIOManager:
234
229
 
235
230
  _dynamic_concurrency_loop: ___dynamic_concurrency_loop_spec[typing_extensions.Self]
236
231
 
237
- class __get_serialized_function_spec(typing_extensions.Protocol[SUPERSELF]):
238
- def __call__(
239
- self,
240
- ) -> tuple[typing.Optional[typing.Any], typing.Optional[collections.abc.Callable[..., typing.Any]]]: ...
241
- async def aio(
242
- self,
243
- ) -> tuple[typing.Optional[typing.Any], typing.Optional[collections.abc.Callable[..., typing.Any]]]: ...
244
-
245
- get_serialized_function: __get_serialized_function_spec[typing_extensions.Self]
246
-
247
- def serialize(self, obj: typing.Any) -> bytes: ...
248
- def deserialize(self, data: bytes) -> typing.Any: ...
249
232
  def serialize_data_format(self, obj: typing.Any, data_format: int) -> bytes: ...
250
233
 
251
234
  class __format_blob_data_spec(typing_extensions.Protocol[SUPERSELF]):
@@ -292,6 +292,7 @@ async def blob_iter(blob_id: str, stub: ModalClientModal) -> AsyncIterator[bytes
292
292
  class FileUploadSpec:
293
293
  source: Callable[[], Union[AbstractContextManager, BinaryIO]]
294
294
  source_description: Any
295
+ source_is_path: bool
295
296
  mount_filename: str
296
297
 
297
298
  use_blob: bool
@@ -328,6 +329,7 @@ def _get_file_upload_spec(
328
329
  return FileUploadSpec(
329
330
  source=source,
330
331
  source_description=source_description,
332
+ source_is_path=isinstance(source_description, Path),
331
333
  mount_filename=mount_filename.as_posix(),
332
334
  use_blob=use_blob,
333
335
  content=content,
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.74.5"
30
+ self, server_url: str, client_type: int, credentials: typing.Optional[tuple[str, str]], version: str = "0.74.7"
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.74.5"
88
+ self, server_url: str, client_type: int, credentials: typing.Optional[tuple[str, str]], version: str = "0.74.7"
89
89
  ): ...
90
90
  def is_closed(self) -> bool: ...
91
91
  @property
modal/config.py CHANGED
@@ -87,7 +87,7 @@ import os
87
87
  import typing
88
88
  import warnings
89
89
  from textwrap import dedent
90
- from typing import Any, Optional
90
+ from typing import Any, Callable, Optional
91
91
 
92
92
  from google.protobuf.empty_pb2 import Empty
93
93
 
@@ -199,6 +199,15 @@ def _to_boolean(x: object) -> bool:
199
199
  return str(x).lower() not in {"", "0", "false"}
200
200
 
201
201
 
202
+ def _check_value(options: list[str]) -> Callable[[str], str]:
203
+ def checker(x: str) -> str:
204
+ if x not in options:
205
+ raise ValueError(f"Must be one of {options}.")
206
+ return x
207
+
208
+ return checker
209
+
210
+
202
211
  class _Setting(typing.NamedTuple):
203
212
  default: typing.Any = None
204
213
  transform: typing.Callable[[str], typing.Any] = lambda x: x # noqa: E731
@@ -232,6 +241,7 @@ _SETTINGS = {
232
241
  "snapshot_debug": _Setting(False, transform=_to_boolean),
233
242
  "cuda_checkpoint_path": _Setting("/__modal/.bin/cuda-checkpoint"), # Used for snapshotting GPU memory.
234
243
  "function_schemas": _Setting(False, transform=_to_boolean),
244
+ "build_validation": _Setting("error", transform=_check_value(["error", "warn", "ignore"])),
235
245
  }
236
246
 
237
247
 
@@ -253,10 +263,17 @@ class Config:
253
263
  profile = _profile
254
264
  s = _SETTINGS[key]
255
265
  env_var_key = "MODAL_" + key.upper()
266
+
267
+ def transform(val: str) -> Any:
268
+ try:
269
+ return s.transform(val)
270
+ except Exception as e:
271
+ raise InvalidError(f"Invalid value for {key} config ({val!r}): {e}")
272
+
256
273
  if use_env and env_var_key in os.environ:
257
- return s.transform(os.environ[env_var_key])
274
+ return transform(os.environ[env_var_key])
258
275
  elif profile in _user_config and key in _user_config[profile]:
259
- return s.transform(_user_config[profile][key])
276
+ return transform(_user_config[profile][key])
260
277
  else:
261
278
  return s.default
262
279
 
modal/mount.py CHANGED
@@ -9,6 +9,7 @@ import sys
9
9
  import sysconfig
10
10
  import time
11
11
  import typing
12
+ import warnings
12
13
  from collections.abc import AsyncGenerator
13
14
  from pathlib import Path, PurePosixPath
14
15
  from typing import Callable, Optional, Sequence, Union
@@ -532,6 +533,17 @@ class _Mount(_Object, type_prefix="mo"):
532
533
  n_finished += 1
533
534
  return mount_file
534
535
 
536
+ # Try to catch cases where user modified their local files (e.g. changed git branches)
537
+ # between triggering a build and Modal actually uploading the file
538
+ if config.get("build_validation") != "ignore" and file_spec.source_is_path:
539
+ mtime = os.stat(file_spec.source_description).st_mtime
540
+ if mtime > resolver.build_start:
541
+ msg = f"{file_spec.source_description} was modified during build process."
542
+ if config.get("build_validation") == "error":
543
+ raise modal.exception.ExecutionError(msg)
544
+ elif config.get("build_validation") == "warn":
545
+ warnings.warn(msg)
546
+
535
547
  request = api_pb2.MountPutFileRequest(sha256_hex=file_spec.sha256_hex)
536
548
  accounted_hashes.add(file_spec.sha256_hex)
537
549
  response = await retry_transient_errors(resolver.client.stub.MountPutFile, request, base_delay=1)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 0.74.5
3
+ Version: 0.74.7
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License: Apache-2.0
@@ -2,7 +2,7 @@ modal/__init__.py,sha256=7wz1AT_bpWJJEzXsAo3QMb7i87y7UGXwfneb0bGDhRg,2502
2
2
  modal/__main__.py,sha256=CgIjP8m1xJjjd4AXc-delmR6LdBCZclw2A_V38CFIio,2870
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=PVs5WDgm0_vZlECf_Ga58L49zceTMKPlUA10YRpPmy8,29026
5
+ modal/_container_entrypoint.py,sha256=DymOImhc3uGRkIq_qXmBsEbWMB4EBMpfuXzz2S4BcGg,29404
6
6
  modal/_functions.py,sha256=EoJ2IbApVoJYELjB0KvXwRV2J6jElhwGHzTbXbXef6A,74712
7
7
  modal/_ipython.py,sha256=TW1fkVOmZL3YYqdS2YlM1hqpf654Yf8ZyybHdBnlhSw,301
8
8
  modal/_location.py,sha256=joiX-0ZeutEUDTrrqLF1GHXCdVLF-rHzstocbMcd_-k,366
@@ -10,7 +10,7 @@ modal/_object.py,sha256=JBIECWdfpRKCaCxVWZbC3Q1kF5Whk_EKvY9f4Y6AFyg,11446
10
10
  modal/_output.py,sha256=Z0nngPh2mKHMQc4MQ92YjVPc3ewOLa3I4dFBlL9nvQY,25656
11
11
  modal/_partial_function.py,sha256=8mmd5lvjZaC7qi0KAnLR1H590MlxNslAE2_Kr9biJUA,39704
12
12
  modal/_pty.py,sha256=JZfPDDpzqICZqtyPI_oMJf_9w-p_lLNuzHhwhodUXio,1329
13
- modal/_resolver.py,sha256=RtoXoYzSllPlFu0D1vel_FWiEmDO7RyToiC2bxeN8ZY,6917
13
+ modal/_resolver.py,sha256=owmQ72ZuGvrTpHxguTMYJyodnfeYcSP0MPV8wvkGa74,7375
14
14
  modal/_resources.py,sha256=5qmcirXUI8dSH926nwkUaeX9H25mqYu9mXD_KuT79-o,1733
15
15
  modal/_serialization.py,sha256=wAgaALThfr-DBV9LMhM4qY_PCH7SRhA9xgoHL2bapBk,22963
16
16
  modal/_traceback.py,sha256=IZQzB3fVlUfMHOSyKUgw0H6qv4yHnpyq-XVCNZKfUdA,5023
@@ -22,12 +22,12 @@ modal/app.py,sha256=4EeD3MXXpaeSFatuWt80xGbMH9cSYS3b9m9z3PQDlwU,48144
22
22
  modal/app.pyi,sha256=SkqXNrdnGIZ4MmNNvpGtzNLoUdyuvi9IjQQR_DRiRHk,26968
23
23
  modal/call_graph.py,sha256=1g2DGcMIJvRy-xKicuf63IVE98gJSnQsr8R_NVMptNc,2581
24
24
  modal/client.py,sha256=U-YKSw0n7J1ZLREt9cbEJCtmHe5YoPKFxl0xlkan2yc,15565
25
- modal/client.pyi,sha256=u3hvKlyHcg7urqfvFwZi7pUgTNkDbBuKJbSz3uMmqAs,7591
25
+ modal/client.pyi,sha256=aosc4b3QOba0inpXwYjn8FmQTcUn4oFHS7rS5gNr4fw,7591
26
26
  modal/cloud_bucket_mount.py,sha256=YOe9nnvSr4ZbeCn587d7_VhE9IioZYRvF9VYQTQux08,5914
27
27
  modal/cloud_bucket_mount.pyi,sha256=30T3K1a89l6wzmEJ_J9iWv9SknoGqaZDx59Xs-ZQcmk,1607
28
28
  modal/cls.py,sha256=GvaNl8R5UsH7Vg88WEOyerdjvZEPK7xxi3nqHlyOW_c,33497
29
29
  modal/cls.pyi,sha256=pTYO9JsRENmsa5pDgzfoRJGm_NpCvEjEx--vs-jJkj8,10902
30
- modal/config.py,sha256=FlqVyh6LVukMahhmEGQVTwWtwtfoPfHqEo3GDn13EOA,11687
30
+ modal/config.py,sha256=nKlX60bC1O-qAEsbGq-efRX1q25h13RyVnoM_0bnhSw,12229
31
31
  modal/container_process.py,sha256=vvyK3DVPUMsuqvkKdUiQ49cDLF9JawGrxpglLk5vfgI,6208
32
32
  modal/container_process.pyi,sha256=bXs2KHe7nxVuLAm6RRBqXCvDKelANGX9gFY8qIuZYDs,2898
33
33
  modal/dict.py,sha256=3Pb45IkfqcDGXu3VVStJVbC_QYk6RTRXrMbZxtByAAk,13354
@@ -45,7 +45,7 @@ modal/image.py,sha256=I-9_YZL0SSfnuGPywa3-4PlxDmJ-53p7ce3gP74SrOA,92877
45
45
  modal/image.pyi,sha256=89zv12C1sFrJs7Es9SnX23_m208ASAdeNGCVTrhjzHI,25632
46
46
  modal/io_streams.py,sha256=YDZVQSDv05DeXg5TwcucC9Rj5hQBx2GXdluan9rIUpw,15467
47
47
  modal/io_streams.pyi,sha256=RpXIWFm6fQkLJRc1uxd0KkQ2wTLCB65jRlyGplU6CQE,5100
48
- modal/mount.py,sha256=_v1VYxryY3BcF4XxyRfOWm7AxAz79D2VRWh5tOHhWuc,31945
48
+ modal/mount.py,sha256=VruBgKrCXD_mmv7iXEfSYERQ3CwH7iqymA3v-5xLGMc,32685
49
49
  modal/mount.pyi,sha256=CmHa7zKSxHA_7-vMQLnGfw_ZXvAvHlafvUEVJcQ1LQA,12535
50
50
  modal/network_file_system.py,sha256=WXdyL7du_fvjvuG6hSAREyJ83sSEP2xSLAIAhBsisdI,14869
51
51
  modal/network_file_system.pyi,sha256=4N3eqMbTSlqmS8VV_aJK-uvrgJC8xnf_YtW5FHfRfc8,8156
@@ -82,8 +82,8 @@ modal/volume.py,sha256=JAWeDvoAG95tMBv-fYIERyHsJPS_X_xGpxRRmYtb6j0,30096
82
82
  modal/volume.pyi,sha256=kTsXarphjZILXci84LQy7EyC84eXUs5-7D62IM5q3eE,12491
83
83
  modal/_runtime/__init__.py,sha256=MIEP8jhXUeGq_eCjYFcqN5b1bxBM4fdk0VESpjWR0fc,28
84
84
  modal/_runtime/asgi.py,sha256=KNarxvZI9z8fnmZl2vbkWTjnoLXs9kqOahkrbsTLkyc,22429
85
- modal/_runtime/container_io_manager.py,sha256=GGej42isNXI55185J1m8gq4wbqpbcY5GKPzpznu0M3E,44648
86
- modal/_runtime/container_io_manager.pyi,sha256=wRd2wHMFru0NmNgiCBVdDTrJGkeVZsZvWwA1fzn8wi8,17009
85
+ modal/_runtime/container_io_manager.py,sha256=0yNO3HTVIM4f338rxJavD8nrRN7KhDpjz1jLux71MRY,43842
86
+ modal/_runtime/container_io_manager.pyi,sha256=3N9TOYa5hfufhJV5IiIhpvJYCeLZe-ne76-XuxcFLW0,16147
87
87
  modal/_runtime/execution_context.py,sha256=73Y5zH_o-MhVCrkJXakYVlFkKqCa2CWvqoHjOfJrJGg,3034
88
88
  modal/_runtime/execution_context.pyi,sha256=TAxQq7uLj7i9r9XbXgFZiSVBWxObFWN-rkssS0I7Vkk,661
89
89
  modal/_runtime/gpu_memory_snapshot.py,sha256=tA3m1d1cwnmHpvpCeN_WijDd6n8byn7LWlpicbIxiOI,3144
@@ -92,7 +92,7 @@ modal/_runtime/user_code_imports.py,sha256=kAv37Pl1TmGKduv0Kozum0xNTD42bDLloSIsT
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=b2TJyKY1Hq7df7M-fo3qlFM95mGdo3dCuqRPPcV5hsE,27445
95
- modal/_utils/blob_utils.py,sha256=RB1G6T7eC1Poe-O45qYLaxwCr2jkM-Q6Nexk1J3wk_w,14505
95
+ modal/_utils/blob_utils.py,sha256=jWJovk4g-YNG3CvkvglOds4a6D1M0Tcal_59v7y9VsM,14591
96
96
  modal/_utils/bytes_io_segment_payload.py,sha256=uunxVJS4PE1LojF_UpURMzVK9GuvmYWRqQo_bxEj5TU,3385
97
97
  modal/_utils/deprecation.py,sha256=EXP1beU4pmEqEzWMLw6E3kUfNfpmNA_VOp6i0EHi93g,4856
98
98
  modal/_utils/docker_utils.py,sha256=h1uETghR40mp_y3fSWuZAfbIASH1HMzuphJHghAL6DU,3722
@@ -145,7 +145,7 @@ modal/requirements/2024.10.txt,sha256=qD-5cVIVM9wXesJ6JC89Ew-3m2KjEElUz3jaw_MddR
145
145
  modal/requirements/PREVIEW.txt,sha256=qD-5cVIVM9wXesJ6JC89Ew-3m2KjEElUz3jaw_MddRo,296
146
146
  modal/requirements/README.md,sha256=9tK76KP0Uph7O0M5oUgsSwEZDj5y-dcUPsnpR0Sc-Ik,854
147
147
  modal/requirements/base-images.json,sha256=57vMSqzMbLBxw5tFWSaMiIkkVEps4JfX5PAtXGnkS4U,740
148
- modal-0.74.5.dist-info/licenses/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
148
+ modal-0.74.7.dist-info/licenses/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
149
149
  modal_docs/__init__.py,sha256=svYKtV8HDwDCN86zbdWqyq5T8sMdGDj0PVlzc2tIxDM,28
150
150
  modal_docs/gen_cli_docs.py,sha256=c1yfBS_x--gL5bs0N4ihMwqwX8l3IBWSkBAKNNIi6bQ,3801
151
151
  modal_docs/gen_reference_docs.py,sha256=cvTgltucqYLLIX84QxAwf51Z5Vc2n6cLxS8VcrxNCAo,6401
@@ -170,9 +170,9 @@ modal_proto/options_pb2_grpc.pyi,sha256=CImmhxHsYnF09iENPoe8S4J-n93jtgUYD2JPAc0y
170
170
  modal_proto/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
171
171
  modal_version/__init__.py,sha256=m94xZNWIjH8oUtJk4l9xfovzDJede2o7X-q0MHVECtM,470
172
172
  modal_version/__main__.py,sha256=2FO0yYQQwDTh6udt1h-cBnGd1c4ZyHnHSI4BksxzVac,105
173
- modal_version/_version_generated.py,sha256=wwyKcRGprZV5T_iYxGUBHKaewrlVo-3zW6j8jEX6Cfs,148
174
- modal-0.74.5.dist-info/METADATA,sha256=BCD7uPmo5H1GPkKhJ2KZPoVLYkMZayKy6xPrMDIX3rI,2473
175
- modal-0.74.5.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
176
- modal-0.74.5.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
177
- modal-0.74.5.dist-info/top_level.txt,sha256=4BWzoKYREKUZ5iyPzZpjqx4G8uB5TWxXPDwibLcVa7k,43
178
- modal-0.74.5.dist-info/RECORD,,
173
+ modal_version/_version_generated.py,sha256=PxczQaV6MUfmLB286M66JcCtkVQoLcQkaEYPUiP6SWU,148
174
+ modal-0.74.7.dist-info/METADATA,sha256=kGNkT7G4UznAdhFmP8zEUJa_uSOeQXAtsPRnbBFysy4,2473
175
+ modal-0.74.7.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
176
+ modal-0.74.7.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
177
+ modal-0.74.7.dist-info/top_level.txt,sha256=4BWzoKYREKUZ5iyPzZpjqx4G8uB5TWxXPDwibLcVa7k,43
178
+ modal-0.74.7.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 = 5 # git: 2e65784
4
+ build_number = 7 # git: 52311ba
File without changes