modal 0.76.2__py3-none-any.whl → 0.76.4__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/cli/app.py CHANGED
@@ -224,10 +224,10 @@ async def history(
224
224
  "Time deployed",
225
225
  "Client",
226
226
  "Deployed by",
227
+ "Commit",
228
+ "Tag",
227
229
  ]
228
230
  rows = []
229
- deployments_with_tags = False
230
- deployments_with_commit_info = False
231
231
  deployments_with_dirty_commit = False
232
232
  for idx, app_stats in enumerate(resp.app_deployment_histories):
233
233
  style = "bold green" if idx == 0 else ""
@@ -239,24 +239,26 @@ async def history(
239
239
  Text(app_stats.deployed_by, style=style),
240
240
  ]
241
241
 
242
- if app_stats.tag:
243
- deployments_with_tags = True
244
- row.append(Text(app_stats.tag, style=style))
245
-
246
242
  if app_stats.commit_info.commit_hash:
247
- deployments_with_commit_info = True
248
243
  short_hash = app_stats.commit_info.commit_hash[:7]
249
244
  if app_stats.commit_info.dirty:
250
245
  deployments_with_dirty_commit = True
251
246
  short_hash = f"{short_hash}*"
252
247
  row.append(Text(short_hash, style=style))
248
+ else:
249
+ row.append(None)
250
+
251
+ if app_stats.tag:
252
+ row.append(Text(app_stats.tag, style=style))
253
+ else:
254
+ row.append(None)
253
255
 
254
256
  rows.append(row)
255
257
 
256
- if deployments_with_tags:
257
- columns.append("Tag")
258
- if deployments_with_commit_info:
259
- columns.append("Commit")
258
+ # Suppress tag information when no deployments used one
259
+ if not any(row[-1] for row in rows):
260
+ rows = [row[:-1] for row in rows]
261
+ columns = columns[:-1]
260
262
 
261
263
  rows = sorted(rows, key=lambda x: int(str(x[0])[1:]), reverse=True)
262
264
  display_table(columns, rows, json)
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.76.2"
30
+ self, server_url: str, client_type: int, credentials: typing.Optional[tuple[str, str]], version: str = "0.76.4"
31
31
  ): ...
32
32
  def is_closed(self) -> bool: ...
33
33
  @property
@@ -86,7 +86,7 @@ class Client:
86
86
  _snapshotted: bool
87
87
 
88
88
  def __init__(
89
- self, server_url: str, client_type: int, credentials: typing.Optional[tuple[str, str]], version: str = "0.76.2"
89
+ self, server_url: str, client_type: int, credentials: typing.Optional[tuple[str, str]], version: str = "0.76.4"
90
90
  ): ...
91
91
  def is_closed(self) -> bool: ...
92
92
  @property
modal/volume.py CHANGED
@@ -194,23 +194,19 @@ class _Volume(_Object, type_prefix="vo"):
194
194
  if metadata and isinstance(metadata, api_pb2.VolumeMetadata):
195
195
  self._metadata = metadata
196
196
  else:
197
- raise TypeError(
198
- "_hydrate_metadata() requires an `api_pb2.VolumeMetadata` to determine volume version"
199
- )
197
+ raise TypeError("_hydrate_metadata() requires an `api_pb2.VolumeMetadata` to determine volume version")
200
198
 
201
199
  def _get_metadata(self) -> Optional[Message]:
202
200
  return self._metadata
203
201
 
204
-
205
202
  @property
206
203
  def _is_v1(self) -> bool:
207
204
  return self._metadata.version in [
208
205
  None,
209
206
  api_pb2.VolumeFsVersion.VOLUME_FS_VERSION_UNSPECIFIED,
210
- api_pb2.VolumeFsVersion.VOLUME_FS_VERSION_V1
207
+ api_pb2.VolumeFsVersion.VOLUME_FS_VERSION_V1,
211
208
  ]
212
209
 
213
-
214
210
  @classmethod
215
211
  @asynccontextmanager
216
212
  async def ephemeral(
@@ -369,21 +365,17 @@ class _Volume(_Object, type_prefix="vo"):
369
365
  file's description. If `recursive` is set to True, list all files and folders under the path
370
366
  recursively.
371
367
  """
372
- from modal_version import major_number, minor_number
373
-
374
- # This allows us to remove the server shim after 0.62 is no longer supported.
375
- deprecation = deprecation_warning if (major_number, minor_number) <= (0, 62) else deprecation_error
376
368
  if path.endswith("**"):
377
369
  msg = (
378
370
  "Glob patterns in `volume get` and `Volume.listdir()` are deprecated. "
379
371
  "Please pass recursive=True instead. For the CLI, just remove the glob suffix."
380
372
  )
381
- deprecation(
373
+ deprecation_error(
382
374
  (2024, 4, 23),
383
375
  msg,
384
376
  )
385
377
  elif path.endswith("*"):
386
- deprecation(
378
+ deprecation_error(
387
379
  (2024, 4, 23),
388
380
  (
389
381
  "Glob patterns in `volume get` and `Volume.listdir()` are deprecated. "
@@ -423,7 +415,6 @@ class _Volume(_Object, type_prefix="vo"):
423
415
  """
424
416
  return self._read_file1(path) if self._is_v1 else self._read_file2(path)
425
417
 
426
-
427
418
  async def _read_file1(self, path: str) -> AsyncIterator[bytes]:
428
419
  req = api_pb2.VolumeGetFileRequest(volume_id=self.object_id, path=path)
429
420
  try:
@@ -438,7 +429,6 @@ class _Volume(_Object, type_prefix="vo"):
438
429
  async for data in blob_iter(response.data_blob_id, self._client.stub):
439
430
  yield data
440
431
 
441
-
442
432
  async def _read_file2(self, path: str) -> AsyncIterator[bytes]:
443
433
  req = api_pb2.VolumeGetFile2Request(volume_id=self.object_id, path=path)
444
434
 
@@ -462,18 +452,15 @@ class _Volume(_Object, type_prefix="vo"):
462
452
  async for value in stream:
463
453
  yield value
464
454
 
465
-
466
455
  @live_method
467
456
  async def read_file_into_fileobj(
468
- self,
469
- path: str,
470
- fileobj: typing.IO[bytes],
471
- progress_cb: Optional[Callable[..., Any]] = None
457
+ self, path: str, fileobj: typing.IO[bytes], progress_cb: Optional[Callable[..., Any]] = None
472
458
  ) -> int:
473
459
  """mdmd:hidden
474
460
  Read volume file into file-like IO object.
475
461
  """
476
462
  if progress_cb is None:
463
+
477
464
  def progress_cb(*_, **__):
478
465
  pass
479
466
 
@@ -482,12 +469,8 @@ class _Volume(_Object, type_prefix="vo"):
482
469
  else:
483
470
  return await self._read_file_into_fileobj2(path, fileobj, progress_cb)
484
471
 
485
-
486
472
  async def _read_file_into_fileobj1(
487
- self,
488
- path: str,
489
- fileobj: typing.IO[bytes],
490
- progress_cb: Callable[..., Any]
473
+ self, path: str, fileobj: typing.IO[bytes], progress_cb: Callable[..., Any]
491
474
  ) -> int:
492
475
  num_bytes_written = 0
493
476
 
@@ -504,12 +487,8 @@ class _Volume(_Object, type_prefix="vo"):
504
487
 
505
488
  return num_bytes_written
506
489
 
507
-
508
490
  async def _read_file_into_fileobj2(
509
- self,
510
- path: str,
511
- fileobj: typing.IO[bytes],
512
- progress_cb: Callable[..., Any]
491
+ self, path: str, fileobj: typing.IO[bytes], progress_cb: Callable[..., Any]
513
492
  ) -> int:
514
493
  req = api_pb2.VolumeGetFile2Request(volume_id=self.object_id, path=path)
515
494
 
@@ -552,7 +531,6 @@ class _Volume(_Object, type_prefix="vo"):
552
531
 
553
532
  return total_size
554
533
 
555
-
556
534
  @live_method
557
535
  async def remove_file(self, path: str, recursive: bool = False) -> None:
558
536
  """Remove a file or directory from a volume."""
@@ -607,13 +585,9 @@ class _Volume(_Object, type_prefix="vo"):
607
585
  ```
608
586
  """
609
587
  return _AbstractVolumeUploadContextManager.resolve(
610
- self._metadata.version,
611
- self.object_id,
612
- self._client,
613
- force=force
588
+ self._metadata.version, self.object_id, self._client, force=force
614
589
  )
615
590
 
616
-
617
591
  @live_method
618
592
  async def _instance_delete(self):
619
593
  await retry_transient_errors(
@@ -642,30 +616,26 @@ class _Volume(_Object, type_prefix="vo"):
642
616
 
643
617
  Volume = synchronize_api(_Volume)
644
618
 
619
+
645
620
  # TODO(dflemstr): Find a way to add ABC or AbstractAsyncContextManager superclasses while keeping synchronicity happy.
646
621
  class _AbstractVolumeUploadContextManager:
647
- async def __aenter__(self):
648
- ...
649
-
650
- async def __aexit__(self, exc_type, exc_val, exc_tb):
651
- ...
622
+ async def __aenter__(self): ...
652
623
 
624
+ async def __aexit__(self, exc_type, exc_val, exc_tb): ...
653
625
 
654
626
  def put_file(
655
627
  self,
656
628
  local_file: Union[Path, str, BinaryIO, BytesIO],
657
629
  remote_path: Union[PurePosixPath, str],
658
630
  mode: Optional[int] = None,
659
- ):
660
- ...
631
+ ): ...
661
632
 
662
633
  def put_directory(
663
634
  self,
664
635
  local_path: Union[Path, str],
665
636
  remote_path: Union[PurePosixPath, str],
666
637
  recursive: bool = True,
667
- ):
668
- ...
638
+ ): ...
669
639
 
670
640
  @staticmethod
671
641
  def resolve(
@@ -673,13 +643,12 @@ class _AbstractVolumeUploadContextManager:
673
643
  object_id: str,
674
644
  client,
675
645
  progress_cb: Optional[Callable[..., Any]] = None,
676
- force: bool = False
646
+ force: bool = False,
677
647
  ) -> "_AbstractVolumeUploadContextManager":
678
-
679
648
  if version in [
680
649
  None,
681
650
  api_pb2.VolumeFsVersion.VOLUME_FS_VERSION_UNSPECIFIED,
682
- api_pb2.VolumeFsVersion.VOLUME_FS_VERSION_V1
651
+ api_pb2.VolumeFsVersion.VOLUME_FS_VERSION_V1,
683
652
  ]:
684
653
  return _VolumeUploadContextManager(object_id, client, progress_cb=progress_cb, force=force)
685
654
  elif version == api_pb2.VolumeFsVersion.VOLUME_FS_VERSION_V2:
@@ -690,6 +659,7 @@ class _AbstractVolumeUploadContextManager:
690
659
 
691
660
  AbstractVolumeUploadContextManager = synchronize_api(_AbstractVolumeUploadContextManager)
692
661
 
662
+
693
663
  class _VolumeUploadContextManager(_AbstractVolumeUploadContextManager):
694
664
  """Context manager for batch-uploading files to a Volume."""
695
665
 
@@ -845,6 +815,7 @@ VolumeUploadContextManager = synchronize_api(_VolumeUploadContextManager)
845
815
 
846
816
  _FileUploader2 = Callable[[asyncio.Semaphore], Awaitable[FileUploadSpec2]]
847
817
 
818
+
848
819
  class _VolumeUploadContextManager2(_AbstractVolumeUploadContextManager):
849
820
  """Context manager for batch-uploading files to a Volume version 2."""
850
821
 
@@ -898,7 +869,6 @@ class _VolumeUploadContextManager2(_AbstractVolumeUploadContextManager):
898
869
  upload_specs = await gen_file_upload_specs()
899
870
  await self._put_file_specs(upload_specs)
900
871
 
901
-
902
872
  def put_file(
903
873
  self,
904
874
  local_file: Union[Path, str, BinaryIO, BytesIO],
@@ -918,17 +888,11 @@ class _VolumeUploadContextManager2(_AbstractVolumeUploadContextManager):
918
888
  def gen():
919
889
  if isinstance(local_file, str) or isinstance(local_file, Path):
920
890
  yield lambda hash_semaphore: FileUploadSpec2.from_path(
921
- local_file,
922
- PurePosixPath(remote_path),
923
- hash_semaphore,
924
- mode
891
+ local_file, PurePosixPath(remote_path), hash_semaphore, mode
925
892
  )
926
893
  else:
927
894
  yield lambda hash_semaphore: FileUploadSpec2.from_fileobj(
928
- local_file,
929
- PurePosixPath(remote_path),
930
- hash_semaphore,
931
- mode or 0o644
895
+ local_file, PurePosixPath(remote_path), hash_semaphore, mode or 0o644
932
896
  )
933
897
 
934
898
  self._uploader_generators.append(gen())
@@ -975,16 +939,15 @@ class _VolumeUploadContextManager2(_AbstractVolumeUploadContextManager):
975
939
  for file_spec in file_specs:
976
940
  blocks = [
977
941
  api_pb2.VolumePutFiles2Request.Block(
978
- contents_sha256=block_sha256,
979
- put_response=put_responses.get(block_sha256)
980
- ) for block_sha256 in file_spec.blocks_sha256
942
+ contents_sha256=block_sha256, put_response=put_responses.get(block_sha256)
943
+ )
944
+ for block_sha256 in file_spec.blocks_sha256
981
945
  ]
982
- files.append(api_pb2.VolumePutFiles2Request.File(
983
- path=file_spec.path,
984
- mode=file_spec.mode,
985
- size=file_spec.size,
986
- blocks=blocks
987
- ))
946
+ files.append(
947
+ api_pb2.VolumePutFiles2Request.File(
948
+ path=file_spec.path, mode=file_spec.mode, size=file_spec.size, blocks=blocks
949
+ )
950
+ )
988
951
 
989
952
  request = api_pb2.VolumePutFiles2Request(
990
953
  volume_id=self._volume_id,
@@ -1001,11 +964,7 @@ class _VolumeUploadContextManager2(_AbstractVolumeUploadContextManager):
1001
964
  break
1002
965
 
1003
966
  await _put_missing_blocks(
1004
- file_specs,
1005
- response.missing_blocks,
1006
- put_responses,
1007
- self._put_concurrency,
1008
- self._progress_cb
967
+ file_specs, response.missing_blocks, put_responses, self._put_concurrency, self._progress_cb
1009
968
  )
1010
969
  else:
1011
970
  raise RuntimeError("Did not succeed at uploading all files despite supplying all missing blocks")
@@ -1023,7 +982,7 @@ async def _put_missing_blocks(
1023
982
  missing_blocks: list,
1024
983
  put_responses: dict[bytes, bytes],
1025
984
  put_concurrency: int,
1026
- progress_cb: Callable[..., Any]
985
+ progress_cb: Callable[..., Any],
1027
986
  ):
1028
987
  @dataclass
1029
988
  class FileProgress:
@@ -1038,7 +997,7 @@ async def _put_missing_blocks(
1038
997
  async def put_missing_block(
1039
998
  # TODO(dflemstr): Type is `api_pb2.VolumePutFiles2Response.MissingBlock` but synchronicity gets confused
1040
999
  # by the nested class (?)
1041
- missing_block
1000
+ missing_block,
1042
1001
  ) -> (bytes, bytes):
1043
1002
  # Lazily import to keep the eager loading time of this module down
1044
1003
  from ._utils.bytes_io_segment_payload import BytesIOSegmentPayload
@@ -1067,8 +1026,8 @@ async def _put_missing_blocks(
1067
1026
  block_start,
1068
1027
  block_length,
1069
1028
  # limit chunk size somewhat to not keep event loop busy for too long
1070
- chunk_size=256*1024,
1071
- progress_report_cb=task_progress_cb
1029
+ chunk_size=256 * 1024,
1030
+ progress_report_cb=task_progress_cb,
1072
1031
  )
1073
1032
 
1074
1033
  async with ClientSessionRegistry.get_session().put(
@@ -1085,10 +1044,7 @@ async def _put_missing_blocks(
1085
1044
 
1086
1045
  return block_sha256, resp_data
1087
1046
 
1088
- tasks = [
1089
- asyncio.create_task(put_missing_block(missing_block))
1090
- for missing_block in missing_blocks
1091
- ]
1047
+ tasks = [asyncio.create_task(put_missing_block(missing_block)) for missing_block in missing_blocks]
1092
1048
  for task_result in asyncio.as_completed(tasks):
1093
1049
  digest, resp = await task_result
1094
1050
  put_responses[digest] = resp
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 0.76.2
3
+ Version: 0.76.4
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License: Apache-2.0
@@ -22,7 +22,7 @@ modal/app.py,sha256=xojuGZv4LaQwZU5ntj7WbmMjeNuB9Gll8Mzqe2LyiEs,51323
22
22
  modal/app.pyi,sha256=zNwR1_2LpmQc9AhemuAeVdk90XNYDw9keOkXAwAATeA,28732
23
23
  modal/call_graph.py,sha256=1g2DGcMIJvRy-xKicuf63IVE98gJSnQsr8R_NVMptNc,2581
24
24
  modal/client.py,sha256=o-aQThHpvDHUzg_kUafyhWzACViUBhY2WLZ2EitnSHA,16787
25
- modal/client.pyi,sha256=p2n_YI6rAsSQJ5_UEEFhixrcErfM4JwQ_8Z3iDr9le4,8383
25
+ modal/client.pyi,sha256=r3nU3OnZUoj5JW9qEMmXoiTZZiCCXrpM5F6lDHh3BtY,8383
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=LZMQdFZ06LpbLDbsCJknniU-393Jb44E1lqveLVM8F8,38365
@@ -78,7 +78,7 @@ modal/snapshot.pyi,sha256=dIEBdTPb7O3VwkQ8TMPjfyU17RLuS9i0DnACxxHy8X4,676
78
78
  modal/stream_type.py,sha256=A6320qoAAWhEfwOCZfGtymQTu5AfLfJXXgARqooTPvY,417
79
79
  modal/token_flow.py,sha256=0_4KabXKsuE4OXTJ1OuLOtA-b1sesShztMZkkRFK7tA,7605
80
80
  modal/token_flow.pyi,sha256=ILbRv6JsZq-jK8jcJM7eB74e0PsbzwBm7hyPcV9lBlQ,2121
81
- modal/volume.py,sha256=DFkdjipvjmWvedd1FL_CjIwyfT7QN-VxusJ9O3fVCw4,44206
81
+ modal/volume.py,sha256=DRmaIYwuRF3h1ZePevdYbHdwFUQRZgK0gaytkEkLAWg,43568
82
82
  modal/volume.pyi,sha256=9hPIMRBzGZycVL8uRfGpjSmNu_pCbkGAOyrnE86bU2Y,21113
83
83
  modal/_runtime/__init__.py,sha256=MIEP8jhXUeGq_eCjYFcqN5b1bxBM4fdk0VESpjWR0fc,28
84
84
  modal/_runtime/asgi.py,sha256=_2xSTsDD27Cit7xnMs4lzkJA2wzer2_N4Oa3BkXFzVA,22521
@@ -117,7 +117,7 @@ modal/_vendor/tblib.py,sha256=g1O7QUDd3sDoLd8YPFltkXkih7r_fyZOjgmGuligv3s,9722
117
117
  modal/cli/__init__.py,sha256=6FRleWQxBDT19y7OayO4lBOzuL6Bs9r0rLINYYYbHwQ,769
118
118
  modal/cli/_download.py,sha256=tV8JFkncTtQKh85bSguQg6AW5aRRlynf-rvyN7ruigc,4337
119
119
  modal/cli/_traceback.py,sha256=4ywtmFcmPnY3tqb4-3fA061N2tRiM01xs8fSagtkwhE,7293
120
- modal/cli/app.py,sha256=87LWg3bTQQIHFOqs8iiJYD_X03omXBZ6lFYR0rMJV-I,8433
120
+ modal/cli/app.py,sha256=JH0_sMGMrG0qA9ToY1RztP8MT0QHX5nZpAH02LpNYcs,8432
121
121
  modal/cli/cluster.py,sha256=EBDhkzfOtPSbwknYdYPBGYvRAwl4Gm7OJkD6_zxrcus,3106
122
122
  modal/cli/config.py,sha256=QvFsqO4eUOtI7d_pQAOAyfq_ZitjhPtav3C6GIDQcZM,1680
123
123
  modal/cli/container.py,sha256=FYwEgjf93j4NMorAjGbSV98i1wpebqdAeNU1wfrFp1k,3668
@@ -146,7 +146,7 @@ modal/requirements/2024.10.txt,sha256=qD-5cVIVM9wXesJ6JC89Ew-3m2KjEElUz3jaw_MddR
146
146
  modal/requirements/PREVIEW.txt,sha256=qD-5cVIVM9wXesJ6JC89Ew-3m2KjEElUz3jaw_MddRo,296
147
147
  modal/requirements/README.md,sha256=9tK76KP0Uph7O0M5oUgsSwEZDj5y-dcUPsnpR0Sc-Ik,854
148
148
  modal/requirements/base-images.json,sha256=57vMSqzMbLBxw5tFWSaMiIkkVEps4JfX5PAtXGnkS4U,740
149
- modal-0.76.2.dist-info/licenses/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
149
+ modal-0.76.4.dist-info/licenses/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
150
150
  modal_docs/__init__.py,sha256=svYKtV8HDwDCN86zbdWqyq5T8sMdGDj0PVlzc2tIxDM,28
151
151
  modal_docs/gen_cli_docs.py,sha256=c1yfBS_x--gL5bs0N4ihMwqwX8l3IBWSkBAKNNIi6bQ,3801
152
152
  modal_docs/gen_reference_docs.py,sha256=d_CQUGQ0rfw28u75I2mov9AlS773z9rG40-yq5o7g2U,6359
@@ -171,9 +171,9 @@ 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=u-X2s_2GMkprLryPgSYm4nwqxeDjYDm_2mJ3SGySns4,470
173
173
  modal_version/__main__.py,sha256=2FO0yYQQwDTh6udt1h-cBnGd1c4ZyHnHSI4BksxzVac,105
174
- modal_version/_version_generated.py,sha256=uJN3Y7EJj0nBEjsfulQdKiMV7A9NbnmHYksfOTffgyY,148
175
- modal-0.76.2.dist-info/METADATA,sha256=iCYEhmi87CU0xMH18BQ8WAjCorIDnLy5lx-AM88dssg,2450
176
- modal-0.76.2.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
177
- modal-0.76.2.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
178
- modal-0.76.2.dist-info/top_level.txt,sha256=4BWzoKYREKUZ5iyPzZpjqx4G8uB5TWxXPDwibLcVa7k,43
179
- modal-0.76.2.dist-info/RECORD,,
174
+ modal_version/_version_generated.py,sha256=7iBCnOznnSgAM0IT8NXFVsQn9fAJbIohVT-badmMAis,148
175
+ modal-0.76.4.dist-info/METADATA,sha256=fVcPU0QU4KLk1RX4hZOYdZHHBO0WfflaoLEZF2ywcTo,2450
176
+ modal-0.76.4.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
177
+ modal-0.76.4.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
178
+ modal-0.76.4.dist-info/top_level.txt,sha256=4BWzoKYREKUZ5iyPzZpjqx4G8uB5TWxXPDwibLcVa7k,43
179
+ modal-0.76.4.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 = 2 # git: 88d20e2
4
+ build_number = 4 # git: 895899b
File without changes