modal 1.0.1.dev4__py3-none-any.whl → 1.0.2.dev0__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/_functions.py CHANGED
@@ -99,6 +99,7 @@ if TYPE_CHECKING:
99
99
  import modal.cls
100
100
  import modal.partial_function
101
101
 
102
+ MAX_INTERNAL_FAILURE_COUNT = 8
102
103
 
103
104
  @dataclasses.dataclass
104
105
  class _RetryContext:
@@ -348,10 +349,14 @@ class _InputPlaneInvocation:
348
349
  stub: ModalClientModal,
349
350
  attempt_token: str,
350
351
  client: _Client,
352
+ input_item: api_pb2.FunctionPutInputsItem,
353
+ function_id: str,
351
354
  ):
352
355
  self.stub = stub
353
356
  self.client = client # Used by the deserializer.
354
357
  self.attempt_token = attempt_token
358
+ self.input_item = input_item
359
+ self.function_id = function_id
355
360
 
356
361
  @staticmethod
357
362
  async def create(
@@ -365,36 +370,55 @@ class _InputPlaneInvocation:
365
370
  stub = await client.get_stub(input_plane_url)
366
371
 
367
372
  function_id = function.object_id
368
- item = await _create_input(args, kwargs, stub, method_name=function._use_method_name)
373
+ input_item = await _create_input(args, kwargs, stub, method_name=function._use_method_name)
369
374
 
370
375
  request = api_pb2.AttemptStartRequest(
371
376
  function_id=function_id,
372
377
  parent_input_id=current_input_id() or "",
373
- input=item,
378
+ input=input_item,
374
379
  )
375
380
  response = await retry_transient_errors(stub.AttemptStart, request)
376
381
  attempt_token = response.attempt_token
377
382
 
378
- return _InputPlaneInvocation(stub, attempt_token, client)
383
+ return _InputPlaneInvocation(stub, attempt_token, client, input_item, function_id)
379
384
 
380
385
  async def run_function(self) -> Any:
381
- # TODO(nathan): add retry logic
386
+ # This will retry when the server returns GENERIC_STATUS_INTERNAL_FAILURE, i.e. lost inputs or worker preemption
387
+ # TODO(ryan): add logic to retry for user defined retry policy
388
+ internal_failure_count = 0
382
389
  while True:
383
- request = api_pb2.AttemptAwaitRequest(
390
+ await_request = api_pb2.AttemptAwaitRequest(
384
391
  attempt_token=self.attempt_token,
385
392
  timeout_secs=OUTPUTS_TIMEOUT,
386
393
  requested_at=time.time(),
387
394
  )
388
- response: api_pb2.AttemptAwaitResponse = await retry_transient_errors(
395
+ await_response: api_pb2.AttemptAwaitResponse = await retry_transient_errors(
389
396
  self.stub.AttemptAwait,
390
- request,
397
+ await_request,
391
398
  attempt_timeout=OUTPUTS_TIMEOUT + ATTEMPT_TIMEOUT_GRACE_PERIOD,
392
399
  )
393
400
 
394
- if response.HasField("output"):
395
- return await _process_result(
396
- response.output.result, response.output.data_format, self.stub, self.client
401
+ try:
402
+ if await_response.HasField("output"):
403
+ return await _process_result(
404
+ await_response.output.result, await_response.output.data_format, self.stub, self.client
405
+ )
406
+ except InternalFailure as e:
407
+ internal_failure_count += 1
408
+ # Limit the number of times we retry
409
+ if internal_failure_count >= MAX_INTERNAL_FAILURE_COUNT:
410
+ raise e
411
+ # For system failures on the server, we retry immediately,
412
+ # and the failure does not count towards the retry policy.
413
+ retry_request = api_pb2.AttemptRetryRequest(
414
+ function_id=self.function_id,
415
+ parent_input_id=current_input_id() or "",
416
+ input=self.input_item,
417
+ attempt_token=self.attempt_token,
397
418
  )
419
+ # TODO(ryan): Add exponential backoff?
420
+ retry_response = await retry_transient_errors(self.stub.AttemptRetry, retry_request)
421
+ self.attempt_token = retry_response.attempt_token
398
422
 
399
423
 
400
424
  # Wrapper type for api_pb2.FunctionStats
modal/_output.py CHANGED
@@ -32,6 +32,7 @@ from rich.progress import (
32
32
  from rich.spinner import Spinner
33
33
  from rich.text import Text
34
34
 
35
+ from modal._utils.time_utils import timestamp_to_local
35
36
  from modal_proto import api_pb2
36
37
 
37
38
  from ._utils.grpc_utils import RETRYABLE_GRPC_STATUS_CODES, retry_transient_errors
@@ -81,22 +82,27 @@ def download_progress_bar() -> Progress:
81
82
  )
82
83
 
83
84
 
84
- class LineBufferedOutput(io.StringIO):
85
+ class LineBufferedOutput:
85
86
  """Output stream that buffers lines and passes them to a callback."""
86
87
 
87
88
  LINE_REGEX = re.compile("(\r\n|\r|\n)")
88
89
 
89
- def __init__(self, callback: Callable[[str], None]):
90
+ def __init__(self, callback: Callable[[str], None], show_timestamps: bool):
90
91
  self._callback = callback
91
92
  self._buf = ""
93
+ self._show_timestamps = show_timestamps
92
94
 
93
- def write(self, data: str):
94
- chunks = self.LINE_REGEX.split(self._buf + data)
95
+ def write(self, log: api_pb2.TaskLogs):
96
+ chunks = self.LINE_REGEX.split(self._buf + log.data)
95
97
 
96
98
  # re.split("(<exp>)") returns the matched groups, and also the separators.
97
99
  # e.g. re.split("(+)", "a+b") returns ["a", "+", "b"].
98
100
  # This means that chunks is guaranteed to be odd in length.
99
101
 
102
+ if self._show_timestamps:
103
+ for i in range(0, len(chunks) - 1, 2):
104
+ chunks[i] = f"{timestamp_to_local(log.timestamp)} {chunks[i]}"
105
+
100
106
  completed_lines = "".join(chunks[:-1])
101
107
  remainder = chunks[-1]
102
108
 
@@ -136,12 +142,14 @@ class OutputManager:
136
142
  _app_page_url: str | None
137
143
  _show_image_logs: bool
138
144
  _status_spinner_live: Live | None
145
+ _show_timestamps: bool
139
146
 
140
147
  def __init__(
141
148
  self,
142
149
  *,
143
150
  stdout: io.TextIOWrapper | None = None,
144
151
  status_spinner_text: str = "Running app...",
152
+ show_timestamps: bool = False,
145
153
  ):
146
154
  self._stdout = stdout or sys.stdout
147
155
  self._console = Console(file=stdout, highlight=False)
@@ -156,6 +164,7 @@ class OutputManager:
156
164
  self._app_page_url = None
157
165
  self._show_image_logs = False
158
166
  self._status_spinner_live = None
167
+ self._show_timestamps = show_timestamps
159
168
 
160
169
  @classmethod
161
170
  def disable(cls):
@@ -355,9 +364,9 @@ class OutputManager:
355
364
  async def put_log_content(self, log: api_pb2.TaskLogs):
356
365
  stream = self._line_buffers.get(log.file_descriptor)
357
366
  if stream is None:
358
- stream = LineBufferedOutput(functools.partial(self._print_log, log.file_descriptor))
367
+ stream = LineBufferedOutput(functools.partial(self._print_log, log.file_descriptor), self._show_timestamps)
359
368
  self._line_buffers[log.file_descriptor] = stream
360
- stream.write(log.data)
369
+ stream.write(log)
361
370
 
362
371
  def flush_lines(self):
363
372
  for stream in self._line_buffers.values():
@@ -0,0 +1,15 @@
1
+ # Copyright Modal Labs 2025
2
+ from datetime import datetime
3
+ from typing import Optional
4
+
5
+
6
+ def timestamp_to_local(ts: float, isotz: bool = True) -> Optional[str]:
7
+ if ts > 0:
8
+ locale_tz = datetime.now().astimezone().tzinfo
9
+ dt = datetime.fromtimestamp(ts, tz=locale_tz)
10
+ if isotz:
11
+ return dt.isoformat(sep=" ", timespec="seconds")
12
+ else:
13
+ return f"{datetime.strftime(dt, '%Y-%m-%d %H:%M')} {locale_tz.tzname(dt)}"
14
+ else:
15
+ return None
modal/cli/app.py CHANGED
@@ -15,7 +15,8 @@ from modal.client import _Client
15
15
  from modal.environments import ensure_env
16
16
  from modal_proto import api_pb2
17
17
 
18
- from .utils import ENV_OPTION, display_table, get_app_id_from_name, stream_app_logs, timestamp_to_local
18
+ from .._utils.time_utils import timestamp_to_local
19
+ from .utils import ENV_OPTION, display_table, get_app_id_from_name, stream_app_logs
19
20
 
20
21
  APP_IDENTIFIER = Argument("", help="App name or ID")
21
22
  NAME_OPTION = typer.Option("", "-n", "--name", help="Deprecated: Pass App name as a positional argument")
@@ -84,6 +85,7 @@ def logs(
84
85
  app_identifier: str = APP_IDENTIFIER,
85
86
  *,
86
87
  env: Optional[str] = ENV_OPTION,
88
+ timestamps: bool = typer.Option(False, "--timestamps", help="Show timestamps for each log line"),
87
89
  ):
88
90
  """Show App logs, streaming while active.
89
91
 
@@ -103,7 +105,7 @@ def logs(
103
105
 
104
106
  """
105
107
  app_id = get_app_id(app_identifier, env)
106
- stream_app_logs(app_id)
108
+ stream_app_logs(app_id, show_timestamps=timestamps)
107
109
 
108
110
 
109
111
  @app_cli.command("rollback", no_args_is_help=True, context_settings={"ignore_unknown_options": True})
modal/cli/cluster.py CHANGED
@@ -8,7 +8,8 @@ from rich.text import Text
8
8
  from modal._object import _get_environment_name
9
9
  from modal._pty import get_pty_info
10
10
  from modal._utils.async_utils import synchronizer
11
- from modal.cli.utils import ENV_OPTION, display_table, is_tty, timestamp_to_local
11
+ from modal._utils.time_utils import timestamp_to_local
12
+ from modal.cli.utils import ENV_OPTION, display_table, is_tty
12
13
  from modal.client import _Client
13
14
  from modal.config import config
14
15
  from modal.container_process import _ContainerProcess
modal/cli/container.py CHANGED
@@ -8,7 +8,8 @@ from modal._object import _get_environment_name
8
8
  from modal._pty import get_pty_info
9
9
  from modal._utils.async_utils import synchronizer
10
10
  from modal._utils.grpc_utils import retry_transient_errors
11
- from modal.cli.utils import ENV_OPTION, display_table, is_tty, stream_app_logs, timestamp_to_local
11
+ from modal._utils.time_utils import timestamp_to_local
12
+ from modal.cli.utils import ENV_OPTION, display_table, is_tty, stream_app_logs
12
13
  from modal.client import _Client
13
14
  from modal.config import config
14
15
  from modal.container_process import _ContainerProcess
modal/cli/dict.py CHANGED
@@ -8,7 +8,8 @@ from typer import Argument, Option, Typer
8
8
  from modal._resolver import Resolver
9
9
  from modal._utils.async_utils import synchronizer
10
10
  from modal._utils.grpc_utils import retry_transient_errors
11
- from modal.cli.utils import ENV_OPTION, YES_OPTION, display_table, timestamp_to_local
11
+ from modal._utils.time_utils import timestamp_to_local
12
+ from modal.cli.utils import ENV_OPTION, YES_OPTION, display_table
12
13
  from modal.client import _Client
13
14
  from modal.dict import _Dict
14
15
  from modal.environments import ensure_env
@@ -17,8 +17,9 @@ from modal._location import display_location
17
17
  from modal._output import OutputManager, ProgressHandler
18
18
  from modal._utils.async_utils import synchronizer
19
19
  from modal._utils.grpc_utils import retry_transient_errors
20
+ from modal._utils.time_utils import timestamp_to_local
20
21
  from modal.cli._download import _volume_download
21
- from modal.cli.utils import ENV_OPTION, YES_OPTION, display_table, timestamp_to_local
22
+ from modal.cli.utils import ENV_OPTION, YES_OPTION, display_table
22
23
  from modal.client import _Client
23
24
  from modal.environments import ensure_env
24
25
  from modal.network_file_system import _NetworkFileSystem
modal/cli/queues.py CHANGED
@@ -8,7 +8,8 @@ from typer import Argument, Option, Typer
8
8
  from modal._resolver import Resolver
9
9
  from modal._utils.async_utils import synchronizer
10
10
  from modal._utils.grpc_utils import retry_transient_errors
11
- from modal.cli.utils import ENV_OPTION, YES_OPTION, display_table, timestamp_to_local
11
+ from modal._utils.time_utils import timestamp_to_local
12
+ from modal.cli.utils import ENV_OPTION, YES_OPTION, display_table
12
13
  from modal.client import _Client
13
14
  from modal.environments import ensure_env
14
15
  from modal.queue import _Queue
modal/cli/secret.py CHANGED
@@ -13,7 +13,8 @@ from typer import Argument
13
13
 
14
14
  from modal._utils.async_utils import synchronizer
15
15
  from modal._utils.grpc_utils import retry_transient_errors
16
- from modal.cli.utils import ENV_OPTION, YES_OPTION, display_table, timestamp_to_local
16
+ from modal._utils.time_utils import timestamp_to_local
17
+ from modal.cli.utils import ENV_OPTION, YES_OPTION, display_table
17
18
  from modal.client import _Client
18
19
  from modal.environments import ensure_env
19
20
  from modal.secret import _Secret
modal/cli/utils.py CHANGED
@@ -1,7 +1,6 @@
1
1
  # Copyright Modal Labs 2022
2
2
  import asyncio
3
3
  from collections.abc import Sequence
4
- from datetime import datetime
5
4
  from json import dumps
6
5
  from typing import Optional, Union
7
6
 
@@ -23,10 +22,13 @@ from ..exception import NotFoundError
23
22
 
24
23
  @synchronizer.create_blocking
25
24
  async def stream_app_logs(
26
- app_id: Optional[str] = None, task_id: Optional[str] = None, app_logs_url: Optional[str] = None
25
+ app_id: Optional[str] = None,
26
+ task_id: Optional[str] = None,
27
+ app_logs_url: Optional[str] = None,
28
+ show_timestamps: bool = False,
27
29
  ):
28
30
  client = await _Client.from_env()
29
- output_mgr = OutputManager(status_spinner_text=f"Tailing logs for {app_id}")
31
+ output_mgr = OutputManager(status_spinner_text=f"Tailing logs for {app_id}", show_timestamps=show_timestamps)
30
32
  try:
31
33
  with output_mgr.show_status_spinner():
32
34
  await get_app_logs_loop(client, output_mgr, app_id=app_id, task_id=task_id, app_logs_url=app_logs_url)
@@ -61,18 +63,6 @@ async def get_app_id_from_name(name: str, env: Optional[str], client: Optional[_
61
63
  return resp.app_id
62
64
 
63
65
 
64
- def timestamp_to_local(ts: float, isotz: bool = True) -> str:
65
- if ts > 0:
66
- locale_tz = datetime.now().astimezone().tzinfo
67
- dt = datetime.fromtimestamp(ts, tz=locale_tz)
68
- if isotz:
69
- return dt.isoformat(sep=" ", timespec="seconds")
70
- else:
71
- return f"{datetime.strftime(dt, '%Y-%m-%d %H:%M')} {locale_tz.tzname(dt)}"
72
- else:
73
- return None
74
-
75
-
76
66
  def _plain(text: Union[Text, str]) -> str:
77
67
  return text.plain if isinstance(text, Text) else text
78
68
 
modal/cli/volume.py CHANGED
@@ -15,8 +15,9 @@ import modal
15
15
  from modal._output import OutputManager, ProgressHandler
16
16
  from modal._utils.async_utils import synchronizer
17
17
  from modal._utils.grpc_utils import retry_transient_errors
18
+ from modal._utils.time_utils import timestamp_to_local
18
19
  from modal.cli._download import _volume_download
19
- from modal.cli.utils import ENV_OPTION, YES_OPTION, display_table, timestamp_to_local
20
+ from modal.cli.utils import ENV_OPTION, YES_OPTION, display_table
20
21
  from modal.client import _Client
21
22
  from modal.environments import ensure_env
22
23
  from modal.volume import _AbstractVolumeUploadContextManager, _Volume
@@ -203,7 +204,7 @@ async def put(
203
204
  vol.object_id,
204
205
  vol._client,
205
206
  progress_cb=progress_handler.progress,
206
- force=force
207
+ force=force,
207
208
  ) as batch:
208
209
  batch.put_directory(local_path, remote_path)
209
210
  except FileExistsError as exc:
@@ -219,7 +220,7 @@ async def put(
219
220
  vol.object_id,
220
221
  vol._client,
221
222
  progress_cb=progress_handler.progress,
222
- force=force
223
+ force=force,
223
224
  ) as batch:
224
225
  batch.put_file(local_path, remote_path)
225
226
 
modal/client.pyi CHANGED
@@ -31,7 +31,7 @@ class _Client:
31
31
  server_url: str,
32
32
  client_type: int,
33
33
  credentials: typing.Optional[tuple[str, str]],
34
- version: str = "1.0.1.dev4",
34
+ version: str = "1.0.2.dev0",
35
35
  ): ...
36
36
  def is_closed(self) -> bool: ...
37
37
  @property
@@ -94,7 +94,7 @@ class Client:
94
94
  server_url: str,
95
95
  client_type: int,
96
96
  credentials: typing.Optional[tuple[str, str]],
97
- version: str = "1.0.1.dev4",
97
+ version: str = "1.0.2.dev0",
98
98
  ): ...
99
99
  def is_closed(self) -> bool: ...
100
100
  @property
modal/functions.pyi CHANGED
@@ -227,11 +227,11 @@ class Function(
227
227
 
228
228
  _call_generator: ___call_generator_spec[typing_extensions.Self]
229
229
 
230
- class __remote_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER, SUPERSELF]):
230
+ class __remote_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER, SUPERSELF]):
231
231
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> ReturnType_INNER: ...
232
232
  async def aio(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> ReturnType_INNER: ...
233
233
 
234
- remote: __remote_spec[modal._functions.ReturnType, modal._functions.P, typing_extensions.Self]
234
+ remote: __remote_spec[modal._functions.P, modal._functions.ReturnType, typing_extensions.Self]
235
235
 
236
236
  class __remote_gen_spec(typing_extensions.Protocol[SUPERSELF]):
237
237
  def __call__(self, /, *args, **kwargs) -> typing.Generator[typing.Any, None, None]: ...
@@ -246,12 +246,12 @@ class Function(
246
246
  self, *args: modal._functions.P.args, **kwargs: modal._functions.P.kwargs
247
247
  ) -> modal._functions.OriginalReturnType: ...
248
248
 
249
- class ___experimental_spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER, SUPERSELF]):
249
+ class ___experimental_spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER, SUPERSELF]):
250
250
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]: ...
251
251
  async def aio(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]: ...
252
252
 
253
253
  _experimental_spawn: ___experimental_spawn_spec[
254
- modal._functions.ReturnType, modal._functions.P, typing_extensions.Self
254
+ modal._functions.P, modal._functions.ReturnType, typing_extensions.Self
255
255
  ]
256
256
 
257
257
  class ___spawn_map_inner_spec(typing_extensions.Protocol[P_INNER, SUPERSELF]):
@@ -260,11 +260,11 @@ class Function(
260
260
 
261
261
  _spawn_map_inner: ___spawn_map_inner_spec[modal._functions.P, typing_extensions.Self]
262
262
 
263
- class __spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER, SUPERSELF]):
263
+ class __spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER, SUPERSELF]):
264
264
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]: ...
265
265
  async def aio(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]: ...
266
266
 
267
- spawn: __spawn_spec[modal._functions.ReturnType, modal._functions.P, typing_extensions.Self]
267
+ spawn: __spawn_spec[modal._functions.P, modal._functions.ReturnType, typing_extensions.Self]
268
268
 
269
269
  def get_raw_f(self) -> collections.abc.Callable[..., typing.Any]: ...
270
270
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.0.1.dev4
3
+ Version: 1.0.2.dev0
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License: Apache-2.0
@@ -3,11 +3,11 @@ modal/__main__.py,sha256=sTJcc9EbDuCKSwg3tL6ZckFw9WWdlkXW8mId1IvJCNc,2846
3
3
  modal/_clustered_functions.py,sha256=kTf-9YBXY88NutC1akI-gCbvf01RhMPCw-zoOI_YIUE,2700
4
4
  modal/_clustered_functions.pyi,sha256=2aWxN2v5WUnj-R-sk6BzJ-3AvggkQGQjwhtvbDH3pds,777
5
5
  modal/_container_entrypoint.py,sha256=2Zx9O_EMJg0H77EdnC2vGKs6uFMWwbP1NLFf-qYmWmU,28962
6
- modal/_functions.py,sha256=HSQ8BVar2RsMD4ud83iUKvE7NSyEoVsTc-3quW8YObA,77149
6
+ modal/_functions.py,sha256=iL1ZVzgLr9xP1UF0rpiazSavdC6DNqnkDU38eaTbk9I,78525
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=KzzzZoM41UQUiY9TKOrft9BtZKgjWG_ukdlyLGjB4UY,10758
10
- modal/_output.py,sha256=Z0nngPh2mKHMQc4MQ92YjVPc3ewOLa3I4dFBlL9nvQY,25656
10
+ modal/_output.py,sha256=LRM9KroHuR7t5pq8iLYjpFz1sQrHYan2kvRDjT6KAw4,26082
11
11
  modal/_partial_function.py,sha256=wzUo_p8arngumPkM5sNIrZ2DluqJl-Z6w5Ds1jHGlyw,39151
12
12
  modal/_pty.py,sha256=JZfPDDpzqICZqtyPI_oMJf_9w-p_lLNuzHhwhodUXio,1329
13
13
  modal/_resolver.py,sha256=-nolqj_p_mx5czVYj1Mazh2IQWpSMrTOGughVJqYfo8,7579
@@ -22,7 +22,7 @@ modal/app.py,sha256=NZ_rJ9TuMfiNiLg8-gOFgufD5flGtXWPHOZI0gdD3hE,46585
22
22
  modal/app.pyi,sha256=4-b_vbe3lNAqQPcMRpQCEDsE1zsVkQRJGUql9B7HvbM,22659
23
23
  modal/call_graph.py,sha256=1g2DGcMIJvRy-xKicuf63IVE98gJSnQsr8R_NVMptNc,2581
24
24
  modal/client.py,sha256=OwISJvkgMb-rHm9Gc4i-7YcDgGiZgwJ7F_PzwZH7a6Q,16847
25
- modal/client.pyi,sha256=LYhZaZrYSv7I_1RYHtR9WeCPPOsvMu0o781DSsR9kb4,8457
25
+ modal/client.pyi,sha256=2S10LK_1EoCSDcYYFPc7w_BxJVLTNabJKLW5ENbtEks,8457
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=dBbeARwOWftlKd1cwtM0cHFtQWSWkwVXwVmOV4w0SyI,37907
@@ -39,7 +39,7 @@ modal/file_io.py,sha256=lcMs_E9Xfm0YX1t9U2wNIBPnqHRxmImqjLW1GHqVmyg,20945
39
39
  modal/file_io.pyi,sha256=oB7x-rKq7bmm8cA7Z7W9C9yeko7KK9m9i5GidFnkGK4,9569
40
40
  modal/file_pattern_matcher.py,sha256=wov-otB5M1oTdrYDtR2_VgacYin2srdtAP4McA1Cqzw,6516
41
41
  modal/functions.py,sha256=kcNHvqeGBxPI7Cgd57NIBBghkfbeFJzXO44WW0jSmao,325
42
- modal/functions.pyi,sha256=5T58OucdNU4I-LqhBdwsWSAGka-Wa8nP2GcZ5K1bOL0,16236
42
+ modal/functions.pyi,sha256=iqdp5ixtOOlm8bF-QYbD_G8VKqSRt_AVLT7AWjpn6pQ,16236
43
43
  modal/gpu.py,sha256=Kbhs_u49FaC2Zi0TjCdrpstpRtT5eZgecynmQi5IZVE,6752
44
44
  modal/image.py,sha256=bGs4FF9TofGQOy2RRjedD2MTyIsmF-9Gdk-I7BitMRw,91832
45
45
  modal/image.pyi,sha256=2xjB6XOZDtm_chDdd90UoIj8pnDt5hCg6bOmu5fNaA4,25625
@@ -110,6 +110,7 @@ modal/_utils/package_utils.py,sha256=LcL2olGN4xaUzu2Tbv-C-Ft9Qp6bsLxEfETOAVd-mjU
110
110
  modal/_utils/pattern_utils.py,sha256=ZUffaECfe2iYBhH6cvCB-0-UWhmEBTZEl_TwG_So3ag,6714
111
111
  modal/_utils/rand_pb_testing.py,sha256=mmVPk1rZldHwHZx0DnHTuHQlRLAiiAYdxjwEJpxvT9c,3900
112
112
  modal/_utils/shell_utils.py,sha256=hWHzv730Br2Xyj6cGPiMZ-198Z3RZuOu3pDXhFSZ22c,2157
113
+ modal/_utils/time_utils.py,sha256=THhRz59gez8jNV1B_eNS2gJJVPPGQSFVlr1esBGQoqg,494
113
114
  modal/_vendor/__init__.py,sha256=MIEP8jhXUeGq_eCjYFcqN5b1bxBM4fdk0VESpjWR0fc,28
114
115
  modal/_vendor/a2wsgi_wsgi.py,sha256=Q1AsjpV_Q_vzQsz_cSqmP9jWzsGsB-ARFU6vpQYml8k,21878
115
116
  modal/_vendor/cloudpickle.py,sha256=avxOIgNKqL9KyPNuIOVQzBm0D1l9ipeB4RrcUMUGmeQ,55216
@@ -117,23 +118,23 @@ modal/_vendor/tblib.py,sha256=g1O7QUDd3sDoLd8YPFltkXkih7r_fyZOjgmGuligv3s,9722
117
118
  modal/cli/__init__.py,sha256=6FRleWQxBDT19y7OayO4lBOzuL6Bs9r0rLINYYYbHwQ,769
118
119
  modal/cli/_download.py,sha256=tV8JFkncTtQKh85bSguQg6AW5aRRlynf-rvyN7ruigc,4337
119
120
  modal/cli/_traceback.py,sha256=4ywtmFcmPnY3tqb4-3fA061N2tRiM01xs8fSagtkwhE,7293
120
- modal/cli/app.py,sha256=vImeK6UT-dA-01pEQ4NQvVQ0eOjdHRG_7-NmqdvSJSY,7639
121
- modal/cli/cluster.py,sha256=EBDhkzfOtPSbwknYdYPBGYvRAwl4Gm7OJkD6_zxrcus,3106
121
+ modal/cli/app.py,sha256=Q4yoPGuNqdWMwIIbjJQflp9RvmgNQQRWBNhCg_Cvi9g,7800
122
+ modal/cli/cluster.py,sha256=nmG3flRs_1VKgJ1Q6nHnt_WpuWDWkGp2He8wA9HeGsQ,3141
122
123
  modal/cli/config.py,sha256=QvFsqO4eUOtI7d_pQAOAyfq_ZitjhPtav3C6GIDQcZM,1680
123
- modal/cli/container.py,sha256=FYwEgjf93j4NMorAjGbSV98i1wpebqdAeNU1wfrFp1k,3668
124
- modal/cli/dict.py,sha256=8Wq3w-UDaywk8EVNdj-ECCNV9TYHqh4kzhUqhhulatM,4593
124
+ modal/cli/container.py,sha256=mRYRCGsP6DiWzm3Az4W5Fcc5Tbl58zOIc62HDzS9TvQ,3703
125
+ modal/cli/dict.py,sha256=012PvKz9YbooE122tWQTcsb9a4lpw5O38DoFNhykcPM,4628
125
126
  modal/cli/entry_point.py,sha256=Ytpsy0MTLQC1RSClI0wNhCbiy6ecPO8555PMmsrxoSc,4377
126
127
  modal/cli/environment.py,sha256=Ayddkiq9jdj3XYDJ8ZmUqFpPPH8xajYlbexRkzGtUcg,4334
127
128
  modal/cli/import_refs.py,sha256=pmzY0hpexx6DtvobNmCOvRqEdS9IriEP4BpMw1TIy2w,13911
128
129
  modal/cli/launch.py,sha256=0_sBu6bv2xJEPWi-rbGS6Ri9ggnkWQvrGlgpYSUBMyY,3097
129
- modal/cli/network_file_system.py,sha256=eq3JnwjbfFNsJodIyANHL06ByYc3BSavzdmu8C96cHA,7948
130
+ modal/cli/network_file_system.py,sha256=DoIdY8I42DjFdTtaYuRKNm7GC6vY0QtA4mk6694fbuU,7983
130
131
  modal/cli/profile.py,sha256=0TYhgRSGUvQZ5LH9nkl6iZllEvAjDniES264dE57wOM,3201
131
- modal/cli/queues.py,sha256=6gTu76dzBtPN5eQVsLrvQpuru5jI9ZCWK5Eh8J8XhaM,4498
132
+ modal/cli/queues.py,sha256=1OzC9HdCkbNz6twF3US4FZmIhuVRQ01GOfBY42ux61A,4533
132
133
  modal/cli/run.py,sha256=DPa-yQ9o7vjqwvs_TAOvVJxS51yVn__ZGCnbkORL37g,23972
133
- modal/cli/secret.py,sha256=Zfscah1gLi8vyMCxYgy1z9lpI-0xfVI_EjyV5ElkL8Q,4967
134
+ modal/cli/secret.py,sha256=oLFEPZoyyeMUKPaJZ9JKKl5mfkQU80DGF9p0atotqig,5002
134
135
  modal/cli/token.py,sha256=mxSgOWakXG6N71hQb1ko61XAR9ZGkTMZD-Txn7gmTac,1924
135
- modal/cli/utils.py,sha256=hZmjyzcPjDnQSkLvycZD2LhGdcsfdZshs_rOU78EpvI,3717
136
- modal/cli/volume.py,sha256=_PJ5Vn_prkLk_x1Lksx4kZySlKWqIn36T2Edd1-h7Mg,10497
136
+ modal/cli/utils.py,sha256=9Q7DIUX78-c19zBQNA7EtkgqIFatvHWUVGHwUIeBX_0,3366
137
+ modal/cli/volume.py,sha256=_QYbB52LLD3Q8eKHFn7bW3Xu0il5A4UkwjjU63hKjEQ,10534
137
138
  modal/cli/programs/__init__.py,sha256=svYKtV8HDwDCN86zbdWqyq5T8sMdGDj0PVlzc2tIxDM,28
138
139
  modal/cli/programs/run_jupyter.py,sha256=44Lpvqk2l3hH-uOkmAOzw60NEsfB5uaRDWDKVshvQhs,2682
139
140
  modal/cli/programs/vscode.py,sha256=KbTAaIXyQBVCDXxXjmBHmKpgXkUw0q4R4KkJvUjCYgk,3380
@@ -146,7 +147,7 @@ modal/requirements/2024.10.txt,sha256=qD-5cVIVM9wXesJ6JC89Ew-3m2KjEElUz3jaw_MddR
146
147
  modal/requirements/PREVIEW.txt,sha256=qD-5cVIVM9wXesJ6JC89Ew-3m2KjEElUz3jaw_MddRo,296
147
148
  modal/requirements/README.md,sha256=9tK76KP0Uph7O0M5oUgsSwEZDj5y-dcUPsnpR0Sc-Ik,854
148
149
  modal/requirements/base-images.json,sha256=57vMSqzMbLBxw5tFWSaMiIkkVEps4JfX5PAtXGnkS4U,740
149
- modal-1.0.1.dev4.dist-info/licenses/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
150
+ modal-1.0.2.dev0.dist-info/licenses/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
150
151
  modal_docs/__init__.py,sha256=svYKtV8HDwDCN86zbdWqyq5T8sMdGDj0PVlzc2tIxDM,28
151
152
  modal_docs/gen_cli_docs.py,sha256=c1yfBS_x--gL5bs0N4ihMwqwX8l3IBWSkBAKNNIi6bQ,3801
152
153
  modal_docs/gen_reference_docs.py,sha256=d_CQUGQ0rfw28u75I2mov9AlS773z9rG40-yq5o7g2U,6359
@@ -169,10 +170,10 @@ modal_proto/options_pb2.pyi,sha256=l7DBrbLO7q3Ir-XDkWsajm0d0TQqqrfuX54i4BMpdQg,1
169
170
  modal_proto/options_pb2_grpc.py,sha256=1oboBPFxaTEXt9Aw7EAj8gXHDCNMhZD2VXqocC9l_gk,159
170
171
  modal_proto/options_pb2_grpc.pyi,sha256=CImmhxHsYnF09iENPoe8S4J-n93jtgUYD2JPAc0yJSI,247
171
172
  modal_proto/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
172
- modal_version/__init__.py,sha256=oGyp944pkdyLRc5vbQGDiYwDeaBD5G6amnXAujX-UBE,120
173
+ modal_version/__init__.py,sha256=eVgGwOcq0pOZ79wRcMg2EbUedzqwB1QqfCQLuyhrJDo,120
173
174
  modal_version/__main__.py,sha256=2FO0yYQQwDTh6udt1h-cBnGd1c4ZyHnHSI4BksxzVac,105
174
- modal-1.0.1.dev4.dist-info/METADATA,sha256=nzAHqppXZsETondjg4FaWmxGxY3aAUZxOzExkNgpjaM,2454
175
- modal-1.0.1.dev4.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
176
- modal-1.0.1.dev4.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
177
- modal-1.0.1.dev4.dist-info/top_level.txt,sha256=4BWzoKYREKUZ5iyPzZpjqx4G8uB5TWxXPDwibLcVa7k,43
178
- modal-1.0.1.dev4.dist-info/RECORD,,
175
+ modal-1.0.2.dev0.dist-info/METADATA,sha256=eSZ35kWG8zk9VWR8kBw94CAL2V7L9WG-dGCBUkdQops,2454
176
+ modal-1.0.2.dev0.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
177
+ modal-1.0.2.dev0.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
178
+ modal-1.0.2.dev0.dist-info/top_level.txt,sha256=4BWzoKYREKUZ5iyPzZpjqx4G8uB5TWxXPDwibLcVa7k,43
179
+ modal-1.0.2.dev0.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.0.1.dev4"
4
+ __version__ = "1.0.2.dev0"