modal 1.0.0.dev20__py3-none-any.whl → 1.0.1__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/_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.py CHANGED
@@ -3,6 +3,7 @@ import asyncio
3
3
  import os
4
4
  import platform
5
5
  import sys
6
+ import urllib.parse
6
7
  import warnings
7
8
  from collections.abc import AsyncGenerator, AsyncIterator, Collection, Mapping
8
9
  from typing import (
@@ -50,8 +51,8 @@ def _get_metadata(client_type: int, credentials: Optional[tuple[str, str]], vers
50
51
  "x-modal-client-version": version,
51
52
  "x-modal-client-type": str(client_type),
52
53
  "x-modal-python-version": python_version,
53
- "x-modal-node": platform.node(),
54
- "x-modal-platform": platform_str,
54
+ "x-modal-node": urllib.parse.quote(platform.node()),
55
+ "x-modal-platform": urllib.parse.quote(platform_str),
55
56
  }
56
57
  if credentials and client_type == api_pb2.CLIENT_TYPE_CLIENT:
57
58
  token_id, token_secret = credentials
modal/client.pyi CHANGED
@@ -27,11 +27,7 @@ class _Client:
27
27
  _snapshotted: bool
28
28
 
29
29
  def __init__(
30
- self,
31
- server_url: str,
32
- client_type: int,
33
- credentials: typing.Optional[tuple[str, str]],
34
- version: str = "1.0.0.dev20",
30
+ self, server_url: str, client_type: int, credentials: typing.Optional[tuple[str, str]], version: str = "1.0.1"
35
31
  ): ...
36
32
  def is_closed(self) -> bool: ...
37
33
  @property
@@ -90,11 +86,7 @@ class Client:
90
86
  _snapshotted: bool
91
87
 
92
88
  def __init__(
93
- self,
94
- server_url: str,
95
- client_type: int,
96
- credentials: typing.Optional[tuple[str, str]],
97
- version: str = "1.0.0.dev20",
89
+ self, server_url: str, client_type: int, credentials: typing.Optional[tuple[str, str]], version: str = "1.0.1"
98
90
  ): ...
99
91
  def is_closed(self) -> bool: ...
100
92
  @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
 
modal/image.py CHANGED
@@ -423,6 +423,9 @@ class _Image(_Object, type_prefix="im"):
423
423
  self._deferred_mounts = other._deferred_mounts
424
424
  self._added_python_source_set = other._added_python_source_set
425
425
 
426
+ def _get_metadata(self) -> Optional[Message]:
427
+ return self._metadata
428
+
426
429
  def _hydrate_metadata(self, metadata: Optional[Message]):
427
430
  env_image_id = config.get("image_id") # set as an env var in containers
428
431
  if env_image_id == self.object_id:
modal/image.pyi CHANGED
@@ -96,6 +96,7 @@ class _Image(modal._object._Object):
96
96
 
97
97
  def _initialize_from_empty(self): ...
98
98
  def _initialize_from_other(self, other: _Image): ...
99
+ def _get_metadata(self) -> typing.Optional[google.protobuf.message.Message]: ...
99
100
  def _hydrate_metadata(self, metadata: typing.Optional[google.protobuf.message.Message]): ...
100
101
  def _add_mount_layer_or_copy(self, mount: modal.mount._Mount, copy: bool = False): ...
101
102
  @property
@@ -352,6 +353,7 @@ class Image(modal.object.Object):
352
353
  def __init__(self, *args, **kwargs): ...
353
354
  def _initialize_from_empty(self): ...
354
355
  def _initialize_from_other(self, other: Image): ...
356
+ def _get_metadata(self) -> typing.Optional[google.protobuf.message.Message]: ...
355
357
  def _hydrate_metadata(self, metadata: typing.Optional[google.protobuf.message.Message]): ...
356
358
  def _add_mount_layer_or_copy(self, mount: modal.mount.Mount, copy: bool = False): ...
357
359
  @property
modal/sandbox.py CHANGED
@@ -738,10 +738,7 @@ class _Sandbox(_Object, type_prefix="sb"):
738
738
  recursive: Optional[bool] = None,
739
739
  timeout: Optional[int] = None,
740
740
  ) -> AsyncIterator[FileWatchEvent]:
741
- """Watch a file or directory in the Sandbox for changes.
742
-
743
- See the [guide](/docs/guide/sandbox-files#file-watching) for usage information.
744
- """
741
+ """Watch a file or directory in the Sandbox for changes."""
745
742
  task_id = await self._get_task_id()
746
743
  async for event in _FileIO.watch(path, self._client, task_id, filter, recursive, timeout):
747
744
  yield event
@@ -775,9 +772,9 @@ class _Sandbox(_Object, type_prefix="sb"):
775
772
  @property
776
773
  def returncode(self) -> Optional[int]:
777
774
  """Return code of the Sandbox process if it has finished running, else `None`."""
778
-
779
- if self._result is None:
775
+ if self._result is None or self._result.status == api_pb2.GenericResult.GENERIC_STATUS_UNSPECIFIED:
780
776
  return None
777
+
781
778
  # Statuses are converted to exitcodes so we can conform to subprocess API.
782
779
  # TODO: perhaps there should be a separate property that returns an enum directly?
783
780
  elif self._result.status == api_pb2.GenericResult.GENERIC_STATUS_TIMEOUT:
@@ -819,8 +816,9 @@ class _Sandbox(_Object, type_prefix="sb"):
819
816
  return
820
817
 
821
818
  for sandbox_info in resp.sandboxes:
819
+ sandbox_info: api_pb2.SandboxInfo
822
820
  obj = _Sandbox._new_hydrated(sandbox_info.id, client, None)
823
- obj._result = sandbox_info.task_info.result
821
+ obj._result = sandbox_info.task_info.result # TODO: send SandboxInfo as metadata to _new_hydrated?
824
822
  yield obj
825
823
 
826
824
  # Fetch the next batch starting from the end of the current one.
modal/snapshot.py CHANGED
@@ -11,13 +11,19 @@ from .client import _Client
11
11
 
12
12
 
13
13
  class _SandboxSnapshot(_Object, type_prefix="sn"):
14
- """A `SandboxSnapshot` object lets you interact with a stored Sandbox snapshot that was created by calling
15
- .snapshot() on a Sandbox instance. This includes both the filesystem and memory state of the original Sandbox at the
16
- time the snapshot was taken.
14
+ """
15
+ > Sandbox memory snapshots are in **early preview**.
16
+
17
+ A `SandboxSnapshot` object lets you interact with a stored Sandbox snapshot that was created by calling
18
+ `._experimental_snapshot()` on a Sandbox instance. This includes both the filesystem and memory state of
19
+ the original Sandbox at the time the snapshot was taken.
17
20
  """
18
21
 
19
22
  @staticmethod
20
23
  async def from_id(sandbox_snapshot_id: str, client: Optional[_Client] = None):
24
+ """
25
+ Construct a `SandboxSnapshot` object from a sandbox snapshot ID.
26
+ """
21
27
  if client is None:
22
28
  client = await _Client.from_env()
23
29
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.0.0.dev20
3
+ Version: 1.0.1
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License: Apache-2.0
@@ -7,7 +7,7 @@ modal/_functions.py,sha256=HSQ8BVar2RsMD4ud83iUKvE7NSyEoVsTc-3quW8YObA,77149
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
@@ -21,8 +21,8 @@ modal/_watcher.py,sha256=K6LYnlmSGQB4tWWI9JADv-tvSvQ1j522FwT71B51CX8,3584
21
21
  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
- modal/client.py,sha256=o-aQThHpvDHUzg_kUafyhWzACViUBhY2WLZ2EitnSHA,16787
25
- modal/client.pyi,sha256=_PywojaIkMx-88tSIJsX-4v-Vz_DwM75H_VoGVlDzEw,8459
24
+ modal/client.py,sha256=OwISJvkgMb-rHm9Gc4i-7YcDgGiZgwJ7F_PzwZH7a6Q,16847
25
+ modal/client.pyi,sha256=tWudNCzkO1nqrup3AslqBUbsl0woIY7hcJ0IjfQfRaI,8381
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,10 +39,10 @@ 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
- modal/image.py,sha256=yfOaKHS0YQtaAB1lb9Dv22fV5jqp_7qeIYLtz5vVc6w,91751
45
- modal/image.pyi,sha256=V0IKbs_fAvkxzFrceJm5W_Dl4s5ATy4LEy8L2tMuemQ,25455
44
+ modal/image.py,sha256=bGs4FF9TofGQOy2RRjedD2MTyIsmF-9Gdk-I7BitMRw,91832
45
+ modal/image.pyi,sha256=2xjB6XOZDtm_chDdd90UoIj8pnDt5hCg6bOmu5fNaA4,25625
46
46
  modal/io_streams.py,sha256=YDZVQSDv05DeXg5TwcucC9Rj5hQBx2GXdluan9rIUpw,15467
47
47
  modal/io_streams.pyi,sha256=1UK6kWLREASQfq-wL9wSp5iqjLU0egRZPDn4LXs1PZY,5136
48
48
  modal/mount.py,sha256=HbpGQbqqT5pTP4dh8j6USWXb2Fr1ro3V1uHIardkya4,30726
@@ -65,7 +65,7 @@ modal/retries.py,sha256=IvNLDM0f_GLUDD5VgEDoN09C88yoxSrCquinAuxT1Sc,5205
65
65
  modal/runner.py,sha256=nvpnU7U2O5d2WqME1QUTTwu-NkSLLwblytlGk7HXPAw,24152
66
66
  modal/runner.pyi,sha256=1AnEu48SUPnLWp3raQ2zJCV5lc85EGLkX2nL0bHWaB0,5162
67
67
  modal/running_app.py,sha256=v61mapYNV1-O-Uaho5EfJlryMLvIT9We0amUOSvSGx8,1188
68
- modal/sandbox.py,sha256=VwbbQPK6e03kp11M8SQWbe6SLWSOwMaFwoQLYdP5EV0,35573
68
+ modal/sandbox.py,sha256=kmhQvM_ACdtQTnLvkMMZ4OJ4ddpPrdbettP06XjavCs,35656
69
69
  modal/sandbox.pyi,sha256=stxwoLcyQNToPISj6umlU8sDUgqzeooLdMs3BwIr740,28195
70
70
  modal/schedule.py,sha256=ewa7hb9NKYnoeSCW2PujZAbGGJL8btX6X3KalCFpc_M,2626
71
71
  modal/scheduler_placement.py,sha256=BAREdOY5HzHpzSBqt6jDVR6YC_jYfHMVqOzkyqQfngU,1235
@@ -73,7 +73,7 @@ modal/secret.py,sha256=I2z-rgKWl_Ix107d2_Y2OWGXdFOuJ7zMOyDfIOdFI1A,10374
73
73
  modal/secret.pyi,sha256=NY_dz0UjiYyn4u4LaBZwPP3Ji7SlTLpEyzrYK2sj9HQ,3103
74
74
  modal/serving.py,sha256=3I3WBeVbzZY258u9PXBCW_dZBgypq3OhwBuTVvlgubE,4423
75
75
  modal/serving.pyi,sha256=YfixTaWikyYpwhnNxCHMZnDDQiPmV1xJ87QF91U_WGU,1924
76
- modal/snapshot.py,sha256=6rQvDP3iX9hdiAudKTy0-m0JESt4kk0q2gusXbaRA-8,1279
76
+ modal/snapshot.py,sha256=E3oxYQkYVRB_LeFBfmUV1Y6vHz8-azXJfC4x7A1QKnI,1455
77
77
  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
@@ -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.0.dev20.dist-info/licenses/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
150
+ modal-1.0.1.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=t4WfZ6bJp0GoMxxM-lbYjN7EPXfXSvjont_ogzKw0xg,121
173
+ modal_version/__init__.py,sha256=zLb15mOpGunJdJzEz-5NWlsW_dKIb-E94_DrwTpoCkI,115
173
174
  modal_version/__main__.py,sha256=2FO0yYQQwDTh6udt1h-cBnGd1c4ZyHnHSI4BksxzVac,105
174
- modal-1.0.0.dev20.dist-info/METADATA,sha256=FL4ukX5pKTOpGdp_GazebHV5fKzTD1ic1NpKV9435KY,2455
175
- modal-1.0.0.dev20.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
176
- modal-1.0.0.dev20.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
177
- modal-1.0.0.dev20.dist-info/top_level.txt,sha256=4BWzoKYREKUZ5iyPzZpjqx4G8uB5TWxXPDwibLcVa7k,43
178
- modal-1.0.0.dev20.dist-info/RECORD,,
175
+ modal-1.0.1.dist-info/METADATA,sha256=QNOl_RRKUePzOoTSDmfjOfWWRcZt0URvDss1EzGDP3o,2449
176
+ modal-1.0.1.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
177
+ modal-1.0.1.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
178
+ modal-1.0.1.dist-info/top_level.txt,sha256=4BWzoKYREKUZ5iyPzZpjqx4G8uB5TWxXPDwibLcVa7k,43
179
+ modal-1.0.1.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.0.dev20"
4
+ __version__ = "1.0.1"