modal 1.1.1.dev26__py3-none-any.whl → 1.1.1.dev28__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

modal/_object.py CHANGED
@@ -48,6 +48,10 @@ class _Object:
48
48
  _is_hydrated: bool
49
49
  _is_rehydrated: bool
50
50
 
51
+ # Not all object subclasses have a meaningful "name" concept
52
+ # So whether they expose this is a matter of having a name property
53
+ _name: Optional[str]
54
+
51
55
  @classmethod
52
56
  def __init_subclass__(cls, type_prefix: Optional[str] = None):
53
57
  super().__init_subclass__()
@@ -68,6 +72,7 @@ class _Object:
68
72
  hydrate_lazily: bool = False,
69
73
  deps: Optional[Callable[..., Sequence["_Object"]]] = None,
70
74
  deduplication_key: Optional[Callable[[], Awaitable[Hashable]]] = None,
75
+ name: Optional[str] = None,
71
76
  ):
72
77
  self._local_uuid = str(uuid.uuid4())
73
78
  self._load = load
@@ -83,6 +88,8 @@ class _Object:
83
88
  self._is_hydrated = False
84
89
  self._is_rehydrated = False
85
90
 
91
+ self._name = name
92
+
86
93
  self._initialize_from_empty()
87
94
 
88
95
  def _unhydrate(self):
@@ -163,10 +170,11 @@ class _Object:
163
170
  hydrate_lazily: bool = False,
164
171
  deps: Optional[Callable[..., Sequence["_Object"]]] = None,
165
172
  deduplication_key: Optional[Callable[[], Awaitable[Hashable]]] = None,
173
+ name: Optional[str] = None,
166
174
  ):
167
175
  # TODO(erikbern): flip the order of the two first arguments
168
176
  obj = _Object.__new__(cls)
169
- obj._init(rep, load, is_another_app, preload, hydrate_lazily, deps, deduplication_key)
177
+ obj._init(rep, load, is_another_app, preload, hydrate_lazily, deps, deduplication_key, name)
170
178
  return obj
171
179
 
172
180
  @staticmethod
modal/_output.py CHANGED
@@ -72,25 +72,6 @@ class FunctionQueuingColumn(ProgressColumn):
72
72
  return Text(str(delta), style="progress.elapsed")
73
73
 
74
74
 
75
- def download_progress_bar() -> Progress:
76
- """
77
- Returns a progress bar suitable for showing file download progress.
78
- Requires passing a `path: str` data field for rendering.
79
- """
80
- return Progress(
81
- TextColumn("[bold white]{task.fields[path]}", justify="right"),
82
- BarColumn(bar_width=None),
83
- "[progress.percentage]{task.percentage:>3.1f}%",
84
- "•",
85
- DownloadColumn(),
86
- "•",
87
- TransferSpeedColumn(),
88
- "•",
89
- TimeRemainingColumn(),
90
- transient=True,
91
- )
92
-
93
-
94
75
  class LineBufferedOutput:
95
76
  """Output stream that buffers lines and passes them to a callback."""
96
77
 
modal/client.pyi CHANGED
@@ -33,7 +33,7 @@ class _Client:
33
33
  server_url: str,
34
34
  client_type: int,
35
35
  credentials: typing.Optional[tuple[str, str]],
36
- version: str = "1.1.1.dev26",
36
+ version: str = "1.1.1.dev28",
37
37
  ):
38
38
  """mdmd:hidden
39
39
  The Modal client object is not intended to be instantiated directly by users.
@@ -164,7 +164,7 @@ class Client:
164
164
  server_url: str,
165
165
  client_type: int,
166
166
  credentials: typing.Optional[tuple[str, str]],
167
- version: str = "1.1.1.dev26",
167
+ version: str = "1.1.1.dev28",
168
168
  ):
169
169
  """mdmd:hidden
170
170
  The Modal client object is not intended to be instantiated directly by users.
modal/dict.py CHANGED
@@ -1,7 +1,10 @@
1
1
  # Copyright Modal Labs 2022
2
2
  from collections.abc import AsyncIterator, Mapping
3
+ from dataclasses import dataclass
4
+ from datetime import datetime
3
5
  from typing import Any, Optional
4
6
 
7
+ from google.protobuf.message import Message
5
8
  from grpclib import GRPCError
6
9
  from synchronicity.async_wrap import asynccontextmanager
7
10
 
@@ -23,6 +26,18 @@ def _serialize_dict(data):
23
26
  return [api_pb2.DictEntry(key=serialize(k), value=serialize(v)) for k, v in data.items()]
24
27
 
25
28
 
29
+ @dataclass
30
+ class DictInfo:
31
+ """Information about the Dict object."""
32
+
33
+ # This dataclass should be limited to information that is unchanging over the lifetime of the Dict,
34
+ # since it is transmitted from the server when the object is hydrated and could be stale when accessed.
35
+
36
+ name: Optional[str]
37
+ created_at: datetime
38
+ created_by: Optional[str]
39
+
40
+
26
41
  class _Dict(_Object, type_prefix="di"):
27
42
  """Distributed dictionary for storage in Modal apps.
28
43
 
@@ -65,12 +80,29 @@ class _Dict(_Object, type_prefix="di"):
65
80
  For more examples, see the [guide](https://modal.com/docs/guide/dicts-and-queues#modal-dicts).
66
81
  """
67
82
 
83
+ _name: Optional[str] = None
84
+ _metadata: Optional[api_pb2.DictMetadata] = None
85
+
68
86
  def __init__(self, data={}):
69
87
  """mdmd:hidden"""
70
88
  raise RuntimeError(
71
89
  "`Dict(...)` constructor is not allowed. Please use `Dict.from_name` or `Dict.ephemeral` instead"
72
90
  )
73
91
 
92
+ @property
93
+ def name(self) -> Optional[str]:
94
+ return self._name
95
+
96
+ def _hydrate_metadata(self, metadata: Optional[Message]):
97
+ if metadata:
98
+ assert isinstance(metadata, api_pb2.DictMetadata)
99
+ self._metadata = metadata
100
+ self._name = metadata.name
101
+
102
+ def _get_metadata(self) -> api_pb2.DictMetadata:
103
+ assert self._metadata
104
+ return self._metadata
105
+
74
106
  @classmethod
75
107
  @asynccontextmanager
76
108
  async def ephemeral(
@@ -112,7 +144,7 @@ class _Dict(_Object, type_prefix="di"):
112
144
  async with TaskContext() as tc:
113
145
  request = api_pb2.DictHeartbeatRequest(dict_id=response.dict_id)
114
146
  tc.infinite_loop(lambda: client.stub.DictHeartbeat(request), sleep=_heartbeat_sleep)
115
- yield cls._new_hydrated(response.dict_id, client, None, is_another_app=True)
147
+ yield cls._new_hydrated(response.dict_id, client, response.metadata, is_another_app=True)
116
148
 
117
149
  @staticmethod
118
150
  def from_name(
@@ -155,7 +187,7 @@ class _Dict(_Object, type_prefix="di"):
155
187
  logger.debug(f"Created dict with id {response.dict_id}")
156
188
  self._hydrate(response.dict_id, resolver.client, response.metadata)
157
189
 
158
- return _Dict._from_loader(_load, "Dict()", is_another_app=True, hydrate_lazily=True)
190
+ return _Dict._from_loader(_load, "Dict()", is_another_app=True, hydrate_lazily=True, name=name)
159
191
 
160
192
  @staticmethod
161
193
  async def lookup(
@@ -209,6 +241,17 @@ class _Dict(_Object, type_prefix="di"):
209
241
  req = api_pb2.DictDeleteRequest(dict_id=obj.object_id)
210
242
  await retry_transient_errors(obj._client.stub.DictDelete, req)
211
243
 
244
+ @live_method
245
+ async def info(self) -> DictInfo:
246
+ """Return information about the Dict object."""
247
+ metadata = self._get_metadata()
248
+ creation_info = metadata.creation_info
249
+ return DictInfo(
250
+ name=metadata.name or None,
251
+ created_at=datetime.fromtimestamp(creation_info.created_at),
252
+ created_by=creation_info.created_by or None,
253
+ )
254
+
212
255
  @live_method
213
256
  async def clear(self) -> None:
214
257
  """Remove all items from the Dict."""
modal/dict.pyi CHANGED
@@ -1,13 +1,37 @@
1
1
  import collections.abc
2
+ import datetime
3
+ import google.protobuf.message
2
4
  import modal._object
3
5
  import modal.client
4
6
  import modal.object
7
+ import modal_proto.api_pb2
5
8
  import synchronicity.combined_types
6
9
  import typing
7
10
  import typing_extensions
8
11
 
9
12
  def _serialize_dict(data): ...
10
13
 
14
+ class DictInfo:
15
+ """Information about the Dict object."""
16
+
17
+ name: typing.Optional[str]
18
+ created_at: datetime.datetime
19
+ created_by: typing.Optional[str]
20
+
21
+ def __init__(
22
+ self, name: typing.Optional[str], created_at: datetime.datetime, created_by: typing.Optional[str]
23
+ ) -> None:
24
+ """Initialize self. See help(type(self)) for accurate signature."""
25
+ ...
26
+
27
+ def __repr__(self):
28
+ """Return repr(self)."""
29
+ ...
30
+
31
+ def __eq__(self, other):
32
+ """Return self==value."""
33
+ ...
34
+
11
35
  class _Dict(modal._object._Object):
12
36
  """Distributed dictionary for storage in Modal apps.
13
37
 
@@ -49,10 +73,18 @@ class _Dict(modal._object._Object):
49
73
 
50
74
  For more examples, see the [guide](https://modal.com/docs/guide/dicts-and-queues#modal-dicts).
51
75
  """
76
+
77
+ _name: typing.Optional[str]
78
+ _metadata: typing.Optional[modal_proto.api_pb2.DictMetadata]
79
+
52
80
  def __init__(self, data={}):
53
81
  """mdmd:hidden"""
54
82
  ...
55
83
 
84
+ @property
85
+ def name(self) -> typing.Optional[str]: ...
86
+ def _hydrate_metadata(self, metadata: typing.Optional[google.protobuf.message.Message]): ...
87
+ def _get_metadata(self) -> modal_proto.api_pb2.DictMetadata: ...
56
88
  @classmethod
57
89
  def ephemeral(
58
90
  cls: type[_Dict],
@@ -131,6 +163,10 @@ class _Dict(modal._object._Object):
131
163
  client: typing.Optional[modal.client._Client] = None,
132
164
  environment_name: typing.Optional[str] = None,
133
165
  ): ...
166
+ async def info(self) -> DictInfo:
167
+ """Return information about the Dict object."""
168
+ ...
169
+
134
170
  async def clear(self) -> None:
135
171
  """Remove all items from the Dict."""
136
172
  ...
@@ -264,10 +300,18 @@ class Dict(modal.object.Object):
264
300
 
265
301
  For more examples, see the [guide](https://modal.com/docs/guide/dicts-and-queues#modal-dicts).
266
302
  """
303
+
304
+ _name: typing.Optional[str]
305
+ _metadata: typing.Optional[modal_proto.api_pb2.DictMetadata]
306
+
267
307
  def __init__(self, data={}):
268
308
  """mdmd:hidden"""
269
309
  ...
270
310
 
311
+ @property
312
+ def name(self) -> typing.Optional[str]: ...
313
+ def _hydrate_metadata(self, metadata: typing.Optional[google.protobuf.message.Message]): ...
314
+ def _get_metadata(self) -> modal_proto.api_pb2.DictMetadata: ...
271
315
  @classmethod
272
316
  def ephemeral(
273
317
  cls: type[Dict],
@@ -388,6 +432,17 @@ class Dict(modal.object.Object):
388
432
 
389
433
  delete: __delete_spec
390
434
 
435
+ class __info_spec(typing_extensions.Protocol[SUPERSELF]):
436
+ def __call__(self, /) -> DictInfo:
437
+ """Return information about the Dict object."""
438
+ ...
439
+
440
+ async def aio(self, /) -> DictInfo:
441
+ """Return information about the Dict object."""
442
+ ...
443
+
444
+ info: __info_spec[typing_extensions.Self]
445
+
391
446
  class __clear_spec(typing_extensions.Protocol[SUPERSELF]):
392
447
  def __call__(self, /) -> None:
393
448
  """Remove all items from the Dict."""
modal/object.pyi CHANGED
@@ -31,6 +31,7 @@ class Object:
31
31
  _client: typing.Optional[modal.client.Client]
32
32
  _is_hydrated: bool
33
33
  _is_rehydrated: bool
34
+ _name: typing.Optional[str]
34
35
 
35
36
  def __init__(self, *args, **kwargs):
36
37
  """mdmd:hidden"""
@@ -54,6 +55,7 @@ class Object:
54
55
  hydrate_lazily: bool = False,
55
56
  deps: typing.Optional[collections.abc.Callable[..., collections.abc.Sequence[Object]]] = None,
56
57
  deduplication_key: typing.Optional[collections.abc.Callable[[], collections.abc.Hashable]] = None,
58
+ name: typing.Optional[str] = None,
57
59
  ): ...
58
60
  def aio(
59
61
  self,
@@ -75,6 +77,7 @@ class Object:
75
77
  deduplication_key: typing.Optional[
76
78
  collections.abc.Callable[[], collections.abc.Awaitable[collections.abc.Hashable]]
77
79
  ] = None,
80
+ name: typing.Optional[str] = None,
78
81
  ): ...
79
82
 
80
83
  _init: ___init_spec[typing_extensions.Self]
@@ -107,6 +110,7 @@ class Object:
107
110
  hydrate_lazily: bool = False,
108
111
  deps: typing.Optional[collections.abc.Callable[..., collections.abc.Sequence[Object]]] = None,
109
112
  deduplication_key: typing.Optional[collections.abc.Callable[[], collections.abc.Hashable]] = None,
113
+ name: typing.Optional[str] = None,
110
114
  ): ...
111
115
  @staticmethod
112
116
  def _get_type_from_id(object_id: str) -> type[Object]: ...
modal/queue.py CHANGED
@@ -3,8 +3,11 @@ import queue # The system library
3
3
  import time
4
4
  import warnings
5
5
  from collections.abc import AsyncGenerator, AsyncIterator
6
+ from dataclasses import dataclass
7
+ from datetime import datetime
6
8
  from typing import Any, Optional
7
9
 
10
+ from google.protobuf.message import Message
8
11
  from grpclib import GRPCError, Status
9
12
  from synchronicity.async_wrap import asynccontextmanager
10
13
 
@@ -21,6 +24,18 @@ from .client import _Client
21
24
  from .exception import InvalidError, RequestSizeError
22
25
 
23
26
 
27
+ @dataclass
28
+ class QueueInfo:
29
+ """Information about the Queue object."""
30
+
31
+ # This dataclass should be limited to information that is unchanging over the lifetime of the Queue,
32
+ # since it is transmitted from the server when the object is hydrated and could be stale when accessed.
33
+
34
+ name: Optional[str]
35
+ created_at: datetime
36
+ created_by: Optional[str]
37
+
38
+
24
39
  class _Queue(_Object, type_prefix="qu"):
25
40
  """Distributed, FIFO queue for data flow in Modal apps.
26
41
 
@@ -94,10 +109,26 @@ class _Queue(_Object, type_prefix="qu"):
94
109
  Partition keys must be non-empty and must not exceed 64 bytes.
95
110
  """
96
111
 
112
+ _metadata: Optional[api_pb2.QueueMetadata] = None
113
+
97
114
  def __init__(self):
98
115
  """mdmd:hidden"""
99
116
  raise RuntimeError("Queue() is not allowed. Please use `Queue.from_name(...)` or `Queue.ephemeral()` instead.")
100
117
 
118
+ @property
119
+ def name(self) -> Optional[str]:
120
+ return self._name
121
+
122
+ def _hydrate_metadata(self, metadata: Optional[Message]):
123
+ if metadata:
124
+ assert isinstance(metadata, api_pb2.QueueMetadata)
125
+ self._metadata = metadata
126
+ self._name = metadata.name
127
+
128
+ def _get_metadata(self) -> api_pb2.QueueMetadata:
129
+ assert self._metadata
130
+ return self._metadata
131
+
101
132
  @staticmethod
102
133
  def validate_partition_key(partition: Optional[str]) -> bytes:
103
134
  if partition is not None:
@@ -142,7 +173,7 @@ class _Queue(_Object, type_prefix="qu"):
142
173
  async with TaskContext() as tc:
143
174
  request = api_pb2.QueueHeartbeatRequest(queue_id=response.queue_id)
144
175
  tc.infinite_loop(lambda: client.stub.QueueHeartbeat(request), sleep=_heartbeat_sleep)
145
- yield cls._new_hydrated(response.queue_id, client, None, is_another_app=True)
176
+ yield cls._new_hydrated(response.queue_id, client, response.metadata, is_another_app=True)
146
177
 
147
178
  @staticmethod
148
179
  def from_name(
@@ -175,7 +206,7 @@ class _Queue(_Object, type_prefix="qu"):
175
206
  response = await resolver.client.stub.QueueGetOrCreate(req)
176
207
  self._hydrate(response.queue_id, resolver.client, response.metadata)
177
208
 
178
- return _Queue._from_loader(_load, "Queue()", is_another_app=True, hydrate_lazily=True)
209
+ return _Queue._from_loader(_load, "Queue()", is_another_app=True, hydrate_lazily=True, name=name)
179
210
 
180
211
  @staticmethod
181
212
  async def lookup(
@@ -222,6 +253,17 @@ class _Queue(_Object, type_prefix="qu"):
222
253
  req = api_pb2.QueueDeleteRequest(queue_id=obj.object_id)
223
254
  await retry_transient_errors(obj._client.stub.QueueDelete, req)
224
255
 
256
+ @live_method
257
+ async def info(self) -> QueueInfo:
258
+ """Return information about the Queue object."""
259
+ metadata = self._get_metadata()
260
+ creation_info = metadata.creation_info
261
+ return QueueInfo(
262
+ name=metadata.name or None,
263
+ created_at=datetime.fromtimestamp(creation_info.created_at),
264
+ created_by=creation_info.created_by or None,
265
+ )
266
+
225
267
  async def _get_nonblocking(self, partition: Optional[str], n_values: int) -> list[Any]:
226
268
  request = api_pb2.QueueGetRequest(
227
269
  queue_id=self.object_id,
modal/queue.pyi CHANGED
@@ -1,11 +1,35 @@
1
1
  import collections.abc
2
+ import datetime
3
+ import google.protobuf.message
2
4
  import modal._object
3
5
  import modal.client
4
6
  import modal.object
7
+ import modal_proto.api_pb2
5
8
  import synchronicity.combined_types
6
9
  import typing
7
10
  import typing_extensions
8
11
 
12
+ class QueueInfo:
13
+ """Information about the Queue object."""
14
+
15
+ name: typing.Optional[str]
16
+ created_at: datetime.datetime
17
+ created_by: typing.Optional[str]
18
+
19
+ def __init__(
20
+ self, name: typing.Optional[str], created_at: datetime.datetime, created_by: typing.Optional[str]
21
+ ) -> None:
22
+ """Initialize self. See help(type(self)) for accurate signature."""
23
+ ...
24
+
25
+ def __repr__(self):
26
+ """Return repr(self)."""
27
+ ...
28
+
29
+ def __eq__(self, other):
30
+ """Return self==value."""
31
+ ...
32
+
9
33
  class _Queue(modal._object._Object):
10
34
  """Distributed, FIFO queue for data flow in Modal apps.
11
35
 
@@ -78,10 +102,17 @@ class _Queue(modal._object._Object):
78
102
 
79
103
  Partition keys must be non-empty and must not exceed 64 bytes.
80
104
  """
105
+
106
+ _metadata: typing.Optional[modal_proto.api_pb2.QueueMetadata]
107
+
81
108
  def __init__(self):
82
109
  """mdmd:hidden"""
83
110
  ...
84
111
 
112
+ @property
113
+ def name(self) -> typing.Optional[str]: ...
114
+ def _hydrate_metadata(self, metadata: typing.Optional[google.protobuf.message.Message]): ...
115
+ def _get_metadata(self) -> modal_proto.api_pb2.QueueMetadata: ...
85
116
  @staticmethod
86
117
  def validate_partition_key(partition: typing.Optional[str]) -> bytes: ...
87
118
  @classmethod
@@ -155,6 +186,10 @@ class _Queue(modal._object._Object):
155
186
  client: typing.Optional[modal.client._Client] = None,
156
187
  environment_name: typing.Optional[str] = None,
157
188
  ): ...
189
+ async def info(self) -> QueueInfo:
190
+ """Return information about the Queue object."""
191
+ ...
192
+
158
193
  async def _get_nonblocking(self, partition: typing.Optional[str], n_values: int) -> list[typing.Any]: ...
159
194
  async def _get_blocking(
160
195
  self, partition: typing.Optional[str], timeout: typing.Optional[float], n_values: int
@@ -335,10 +370,17 @@ class Queue(modal.object.Object):
335
370
 
336
371
  Partition keys must be non-empty and must not exceed 64 bytes.
337
372
  """
373
+
374
+ _metadata: typing.Optional[modal_proto.api_pb2.QueueMetadata]
375
+
338
376
  def __init__(self):
339
377
  """mdmd:hidden"""
340
378
  ...
341
379
 
380
+ @property
381
+ def name(self) -> typing.Optional[str]: ...
382
+ def _hydrate_metadata(self, metadata: typing.Optional[google.protobuf.message.Message]): ...
383
+ def _get_metadata(self) -> modal_proto.api_pb2.QueueMetadata: ...
342
384
  @staticmethod
343
385
  def validate_partition_key(partition: typing.Optional[str]) -> bytes: ...
344
386
  @classmethod
@@ -453,6 +495,17 @@ class Queue(modal.object.Object):
453
495
 
454
496
  delete: __delete_spec
455
497
 
498
+ class __info_spec(typing_extensions.Protocol[SUPERSELF]):
499
+ def __call__(self, /) -> QueueInfo:
500
+ """Return information about the Queue object."""
501
+ ...
502
+
503
+ async def aio(self, /) -> QueueInfo:
504
+ """Return information about the Queue object."""
505
+ ...
506
+
507
+ info: __info_spec[typing_extensions.Self]
508
+
456
509
  class ___get_nonblocking_spec(typing_extensions.Protocol[SUPERSELF]):
457
510
  def __call__(self, /, partition: typing.Optional[str], n_values: int) -> list[typing.Any]: ...
458
511
  async def aio(self, /, partition: typing.Optional[str], n_values: int) -> list[typing.Any]: ...
modal/secret.py CHANGED
@@ -1,12 +1,15 @@
1
1
  # Copyright Modal Labs 2022
2
2
  import os
3
+ from dataclasses import dataclass
4
+ from datetime import datetime
3
5
  from typing import Optional, Union
4
6
 
7
+ from google.protobuf.message import Message
5
8
  from grpclib import GRPCError, Status
6
9
 
7
10
  from modal_proto import api_pb2
8
11
 
9
- from ._object import _get_environment_name, _Object
12
+ from ._object import _get_environment_name, _Object, live_method
10
13
  from ._resolver import Resolver
11
14
  from ._runtime.execution_context import is_local
12
15
  from ._utils.async_utils import synchronize_api
@@ -19,6 +22,18 @@ from .exception import InvalidError, NotFoundError
19
22
  ENV_DICT_WRONG_TYPE_ERR = "the env_dict argument to Secret has to be a dict[str, Union[str, None]]"
20
23
 
21
24
 
25
+ @dataclass
26
+ class SecretInfo:
27
+ """Information about the Secret object."""
28
+
29
+ # This dataclass should be limited to information that is unchanging over the lifetime of the Secret,
30
+ # since it is transmitted from the server when the object is hydrated and could be stale when accessed.
31
+
32
+ name: Optional[str]
33
+ created_at: datetime
34
+ created_by: Optional[str]
35
+
36
+
22
37
  class _Secret(_Object, type_prefix="st"):
23
38
  """Secrets provide a dictionary of environment variables for images.
24
39
 
@@ -29,6 +44,22 @@ class _Secret(_Object, type_prefix="st"):
29
44
  See [the secrets guide page](https://modal.com/docs/guide/secrets) for more information.
30
45
  """
31
46
 
47
+ _metadata: Optional[api_pb2.SecretMetadata] = None
48
+
49
+ @property
50
+ def name(self) -> Optional[str]:
51
+ return self._name
52
+
53
+ def _hydrate_metadata(self, metadata: Optional[Message]):
54
+ if metadata:
55
+ assert isinstance(metadata, api_pb2.SecretMetadata)
56
+ self._metadata = metadata
57
+ self._name = metadata.name
58
+
59
+ def _get_metadata(self) -> api_pb2.SecretMetadata:
60
+ assert self._metadata
61
+ return self._metadata
62
+
32
63
  @staticmethod
33
64
  def from_dict(
34
65
  env_dict: dict[
@@ -202,7 +233,7 @@ class _Secret(_Object, type_prefix="st"):
202
233
  raise
203
234
  self._hydrate(response.secret_id, resolver.client, response.metadata)
204
235
 
205
- return _Secret._from_loader(_load, "Secret()", hydrate_lazily=True)
236
+ return _Secret._from_loader(_load, "Secret()", hydrate_lazily=True, name=name)
206
237
 
207
238
  @staticmethod
208
239
  async def lookup(
@@ -261,5 +292,16 @@ class _Secret(_Object, type_prefix="st"):
261
292
  resp = await retry_transient_errors(client.stub.SecretGetOrCreate, request)
262
293
  return resp.secret_id
263
294
 
295
+ @live_method
296
+ async def info(self) -> SecretInfo:
297
+ """Return information about the Secret object."""
298
+ metadata = self._get_metadata()
299
+ creation_info = metadata.creation_info
300
+ return SecretInfo(
301
+ name=metadata.name or None,
302
+ created_at=datetime.fromtimestamp(creation_info.created_at),
303
+ created_by=creation_info.created_by or None,
304
+ )
305
+
264
306
 
265
307
  Secret = synchronize_api(_Secret)
modal/secret.pyi CHANGED
@@ -1,9 +1,33 @@
1
+ import datetime
2
+ import google.protobuf.message
1
3
  import modal._object
2
4
  import modal.client
3
5
  import modal.object
6
+ import modal_proto.api_pb2
4
7
  import typing
5
8
  import typing_extensions
6
9
 
10
+ class SecretInfo:
11
+ """Information about the Secret object."""
12
+
13
+ name: typing.Optional[str]
14
+ created_at: datetime.datetime
15
+ created_by: typing.Optional[str]
16
+
17
+ def __init__(
18
+ self, name: typing.Optional[str], created_at: datetime.datetime, created_by: typing.Optional[str]
19
+ ) -> None:
20
+ """Initialize self. See help(type(self)) for accurate signature."""
21
+ ...
22
+
23
+ def __repr__(self):
24
+ """Return repr(self)."""
25
+ ...
26
+
27
+ def __eq__(self, other):
28
+ """Return self==value."""
29
+ ...
30
+
7
31
  class _Secret(modal._object._Object):
8
32
  """Secrets provide a dictionary of environment variables for images.
9
33
 
@@ -13,6 +37,13 @@ class _Secret(modal._object._Object):
13
37
 
14
38
  See [the secrets guide page](https://modal.com/docs/guide/secrets) for more information.
15
39
  """
40
+
41
+ _metadata: typing.Optional[modal_proto.api_pb2.SecretMetadata]
42
+
43
+ @property
44
+ def name(self) -> typing.Optional[str]: ...
45
+ def _hydrate_metadata(self, metadata: typing.Optional[google.protobuf.message.Message]): ...
46
+ def _get_metadata(self) -> modal_proto.api_pb2.SecretMetadata: ...
16
47
  @staticmethod
17
48
  def from_dict(env_dict: dict[str, typing.Optional[str]] = {}) -> _Secret:
18
49
  """Create a secret from a str-str dictionary. Values can also be `None`, which is ignored.
@@ -104,6 +135,12 @@ class _Secret(modal._object._Object):
104
135
  """mdmd:hidden"""
105
136
  ...
106
137
 
138
+ async def info(self) -> SecretInfo:
139
+ """Return information about the Secret object."""
140
+ ...
141
+
142
+ SUPERSELF = typing.TypeVar("SUPERSELF", covariant=True)
143
+
107
144
  class Secret(modal.object.Object):
108
145
  """Secrets provide a dictionary of environment variables for images.
109
146
 
@@ -113,10 +150,17 @@ class Secret(modal.object.Object):
113
150
 
114
151
  See [the secrets guide page](https://modal.com/docs/guide/secrets) for more information.
115
152
  """
153
+
154
+ _metadata: typing.Optional[modal_proto.api_pb2.SecretMetadata]
155
+
116
156
  def __init__(self, *args, **kwargs):
117
157
  """mdmd:hidden"""
118
158
  ...
119
159
 
160
+ @property
161
+ def name(self) -> typing.Optional[str]: ...
162
+ def _hydrate_metadata(self, metadata: typing.Optional[google.protobuf.message.Message]): ...
163
+ def _get_metadata(self) -> modal_proto.api_pb2.SecretMetadata: ...
120
164
  @staticmethod
121
165
  def from_dict(env_dict: dict[str, typing.Optional[str]] = {}) -> Secret:
122
166
  """Create a secret from a str-str dictionary. Values can also be `None`, which is ignored.
@@ -240,3 +284,14 @@ class Secret(modal.object.Object):
240
284
  ...
241
285
 
242
286
  create_deployed: __create_deployed_spec
287
+
288
+ class __info_spec(typing_extensions.Protocol[SUPERSELF]):
289
+ def __call__(self, /) -> SecretInfo:
290
+ """Return information about the Secret object."""
291
+ ...
292
+
293
+ async def aio(self, /) -> SecretInfo:
294
+ """Return information about the Secret object."""
295
+ ...
296
+
297
+ info: __info_spec[typing_extensions.Self]
modal/volume.py CHANGED
@@ -11,6 +11,7 @@ import time
11
11
  import typing
12
12
  from collections.abc import AsyncGenerator, AsyncIterator, Generator, Sequence
13
13
  from dataclasses import dataclass
14
+ from datetime import datetime
14
15
  from io import BytesIO
15
16
  from pathlib import Path, PurePosixPath
16
17
  from typing import (
@@ -92,6 +93,18 @@ class FileEntry:
92
93
  )
93
94
 
94
95
 
96
+ @dataclass
97
+ class VolumeInfo:
98
+ """Information about the Volume object."""
99
+
100
+ # This dataclass should be limited to information that is unchanging over the lifetime of the Volume,
101
+ # since it is transmitted from the server when the object is hydrated and could be stale when accessed.
102
+
103
+ name: Optional[str]
104
+ created_at: datetime
105
+ created_by: Optional[str]
106
+
107
+
95
108
  class _Volume(_Object, type_prefix="vo"):
96
109
  """A writeable volume that can be used to share files between one or more Modal functions.
97
110
 
@@ -167,6 +180,19 @@ class _Volume(_Object, type_prefix="vo"):
167
180
  obj = _Volume._from_loader(_load, "Volume()", hydrate_lazily=True, deps=lambda: [self])
168
181
  return obj
169
182
 
183
+ @property
184
+ def name(self) -> Optional[str]:
185
+ return self._name
186
+
187
+ def _hydrate_metadata(self, metadata: Optional[Message]):
188
+ if metadata:
189
+ assert isinstance(metadata, api_pb2.VolumeMetadata)
190
+ self._metadata = metadata
191
+ self._name = metadata.name
192
+
193
+ def _get_metadata(self) -> Optional[Message]:
194
+ return self._metadata
195
+
170
196
  async def _get_lock(self):
171
197
  # To (mostly*) prevent multiple concurrent operations on the same volume, which can cause problems under
172
198
  # some unlikely circumstances.
@@ -181,6 +207,14 @@ class _Volume(_Object, type_prefix="vo"):
181
207
  self._lock = asyncio.Lock()
182
208
  return self._lock
183
209
 
210
+ @property
211
+ def _is_v1(self) -> bool:
212
+ return self._metadata.version in [
213
+ None,
214
+ api_pb2.VolumeFsVersion.VOLUME_FS_VERSION_UNSPECIFIED,
215
+ api_pb2.VolumeFsVersion.VOLUME_FS_VERSION_V1,
216
+ ]
217
+
184
218
  @staticmethod
185
219
  def from_name(
186
220
  name: str,
@@ -220,24 +254,7 @@ class _Volume(_Object, type_prefix="vo"):
220
254
  response = await resolver.client.stub.VolumeGetOrCreate(req)
221
255
  self._hydrate(response.volume_id, resolver.client, response.metadata)
222
256
 
223
- return _Volume._from_loader(_load, "Volume()", hydrate_lazily=True)
224
-
225
- def _hydrate_metadata(self, metadata: Optional[Message]):
226
- if metadata and isinstance(metadata, api_pb2.VolumeMetadata):
227
- self._metadata = metadata
228
- else:
229
- raise TypeError("_hydrate_metadata() requires an `api_pb2.VolumeMetadata` to determine volume version")
230
-
231
- def _get_metadata(self) -> Optional[Message]:
232
- return self._metadata
233
-
234
- @property
235
- def _is_v1(self) -> bool:
236
- return self._metadata.version in [
237
- None,
238
- api_pb2.VolumeFsVersion.VOLUME_FS_VERSION_UNSPECIFIED,
239
- api_pb2.VolumeFsVersion.VOLUME_FS_VERSION_V1,
240
- ]
257
+ return _Volume._from_loader(_load, "Volume()", hydrate_lazily=True, name=name)
241
258
 
242
259
  @classmethod
243
260
  @asynccontextmanager
@@ -338,6 +355,19 @@ class _Volume(_Object, type_prefix="vo"):
338
355
  resp = await retry_transient_errors(client.stub.VolumeGetOrCreate, request)
339
356
  return resp.volume_id
340
357
 
358
+ @live_method
359
+ async def info(self) -> VolumeInfo:
360
+ """Return information about the Volume object."""
361
+ metadata = self._get_metadata()
362
+ if not metadata:
363
+ return VolumeInfo()
364
+ creation_info = metadata.creation_info
365
+ return VolumeInfo(
366
+ name=metadata.name or None,
367
+ created_at=datetime.fromtimestamp(creation_info.created_at) if creation_info.created_at else None,
368
+ created_by=creation_info.created_by or None,
369
+ )
370
+
341
371
  @live_method
342
372
  async def _do_reload(self, lock=True):
343
373
  async with (await self._get_lock()) if lock else asyncnullcontext():
modal/volume.pyi CHANGED
@@ -1,6 +1,7 @@
1
1
  import _io
2
2
  import asyncio.locks
3
3
  import collections.abc
4
+ import datetime
4
5
  import enum
5
6
  import google.protobuf.message
6
7
  import modal._object
@@ -57,6 +58,27 @@ class FileEntry:
57
58
  """Return hash(self)."""
58
59
  ...
59
60
 
61
+ class VolumeInfo:
62
+ """Information about the Volume object."""
63
+
64
+ name: typing.Optional[str]
65
+ created_at: datetime.datetime
66
+ created_by: typing.Optional[str]
67
+
68
+ def __init__(
69
+ self, name: typing.Optional[str], created_at: datetime.datetime, created_by: typing.Optional[str]
70
+ ) -> None:
71
+ """Initialize self. See help(type(self)) for accurate signature."""
72
+ ...
73
+
74
+ def __repr__(self):
75
+ """Return repr(self)."""
76
+ ...
77
+
78
+ def __eq__(self, other):
79
+ """Return self==value."""
80
+ ...
81
+
60
82
  class _Volume(modal._object._Object):
61
83
  """A writeable volume that can be used to share files between one or more Modal functions.
62
84
 
@@ -126,7 +148,13 @@ class _Volume(modal._object._Object):
126
148
  """
127
149
  ...
128
150
 
151
+ @property
152
+ def name(self) -> typing.Optional[str]: ...
153
+ def _hydrate_metadata(self, metadata: typing.Optional[google.protobuf.message.Message]): ...
154
+ def _get_metadata(self) -> typing.Optional[google.protobuf.message.Message]: ...
129
155
  async def _get_lock(self): ...
156
+ @property
157
+ def _is_v1(self) -> bool: ...
130
158
  @staticmethod
131
159
  def from_name(
132
160
  name: str,
@@ -155,10 +183,6 @@ class _Volume(modal._object._Object):
155
183
  """
156
184
  ...
157
185
 
158
- def _hydrate_metadata(self, metadata: typing.Optional[google.protobuf.message.Message]): ...
159
- def _get_metadata(self) -> typing.Optional[google.protobuf.message.Message]: ...
160
- @property
161
- def _is_v1(self) -> bool: ...
162
186
  @classmethod
163
187
  def ephemeral(
164
188
  cls: type[_Volume],
@@ -218,6 +242,10 @@ class _Volume(modal._object._Object):
218
242
  """mdmd:hidden"""
219
243
  ...
220
244
 
245
+ async def info(self) -> VolumeInfo:
246
+ """Return information about the Volume object."""
247
+ ...
248
+
221
249
  async def _do_reload(self, lock=True): ...
222
250
  async def commit(self):
223
251
  """Commit changes to the volume.
@@ -424,12 +452,19 @@ class Volume(modal.object.Object):
424
452
  """
425
453
  ...
426
454
 
455
+ @property
456
+ def name(self) -> typing.Optional[str]: ...
457
+ def _hydrate_metadata(self, metadata: typing.Optional[google.protobuf.message.Message]): ...
458
+ def _get_metadata(self) -> typing.Optional[google.protobuf.message.Message]: ...
459
+
427
460
  class ___get_lock_spec(typing_extensions.Protocol[SUPERSELF]):
428
461
  def __call__(self, /): ...
429
462
  async def aio(self, /): ...
430
463
 
431
464
  _get_lock: ___get_lock_spec[typing_extensions.Self]
432
465
 
466
+ @property
467
+ def _is_v1(self) -> bool: ...
433
468
  @staticmethod
434
469
  def from_name(
435
470
  name: str,
@@ -458,10 +493,6 @@ class Volume(modal.object.Object):
458
493
  """
459
494
  ...
460
495
 
461
- def _hydrate_metadata(self, metadata: typing.Optional[google.protobuf.message.Message]): ...
462
- def _get_metadata(self) -> typing.Optional[google.protobuf.message.Message]: ...
463
- @property
464
- def _is_v1(self) -> bool: ...
465
496
  @classmethod
466
497
  def ephemeral(
467
498
  cls: type[Volume],
@@ -566,6 +597,17 @@ class Volume(modal.object.Object):
566
597
 
567
598
  create_deployed: __create_deployed_spec
568
599
 
600
+ class __info_spec(typing_extensions.Protocol[SUPERSELF]):
601
+ def __call__(self, /) -> VolumeInfo:
602
+ """Return information about the Volume object."""
603
+ ...
604
+
605
+ async def aio(self, /) -> VolumeInfo:
606
+ """Return information about the Volume object."""
607
+ ...
608
+
609
+ info: __info_spec[typing_extensions.Self]
610
+
569
611
  class ___do_reload_spec(typing_extensions.Protocol[SUPERSELF]):
570
612
  def __call__(self, /, lock=True): ...
571
613
  async def aio(self, /, lock=True): ...
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.1.1.dev26
3
+ Version: 1.1.1.dev28
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License: Apache-2.0
@@ -6,8 +6,8 @@ modal/_container_entrypoint.py,sha256=1qBMNY_E9ICC_sRCtillMxmKPsmxJl1J0_qOAG8rH-
6
6
  modal/_functions.py,sha256=c1EeAcHcYP76wHbLomV0mFe73AoL-TUSjJNSDu6CELI,83065
7
7
  modal/_ipython.py,sha256=TW1fkVOmZL3YYqdS2YlM1hqpf654Yf8ZyybHdBnlhSw,301
8
8
  modal/_location.py,sha256=joiX-0ZeutEUDTrrqLF1GHXCdVLF-rHzstocbMcd_-k,366
9
- modal/_object.py,sha256=vzRWhAcFJDM8ZmiUSDgSj9gJhLZJA-wjLVvTl984N4A,11295
10
- modal/_output.py,sha256=4LbNjPyd6spKiwJS-UTrZKnfpIWmdNy7rnDIVcNVwSE,26327
9
+ modal/_object.py,sha256=nCkQeLibSuvVAEIheGaLnUfN5PIh1CGpJCnzPIXymGY,11563
10
+ modal/_output.py,sha256=T7CRq90W09d-WD4ko7T4PBe26JNeAXE1-8HNO9xpNPI,25787
11
11
  modal/_partial_function.py,sha256=B1J4S9W-La0NHaVmY1aCuH0E3QxJHIX6ZWY5eNTQ7io,37142
12
12
  modal/_pty.py,sha256=JZfPDDpzqICZqtyPI_oMJf_9w-p_lLNuzHhwhodUXio,1329
13
13
  modal/_resolver.py,sha256=2RWvm34cNSnbv1v7izJMNZgfvpLDD6LzaBlr0lIrLnY,7364
@@ -22,7 +22,7 @@ modal/app.py,sha256=BBR2NmGzZbFGfhKAmtzllD0o4TbVDBbOEs0O2ysSdQo,48277
22
22
  modal/app.pyi,sha256=h6JtBA6a7wobdZAuS3QuXrWCUZqfyKPuGV3XdjCqT3k,43753
23
23
  modal/call_graph.py,sha256=1g2DGcMIJvRy-xKicuf63IVE98gJSnQsr8R_NVMptNc,2581
24
24
  modal/client.py,sha256=kyAIVB3Ay-XKJizQ_1ufUFB__EagV0MLmHJpyYyJ7J0,18636
25
- modal/client.pyi,sha256=ft7F2zZkCFWeifBXbRdMfWpa1UGC4nfw6rEqThzh4xo,15831
25
+ modal/client.pyi,sha256=lLCQ-T2OTowy_xclR3HuOrUHday0qON2GzIglWlsks4,15831
26
26
  modal/cloud_bucket_mount.py,sha256=YOe9nnvSr4ZbeCn587d7_VhE9IioZYRvF9VYQTQux08,5914
27
27
  modal/cloud_bucket_mount.pyi,sha256=-qSfYAQvIoO_l2wsCCGTG5ZUwQieNKXdAO00yP1-LYU,7394
28
28
  modal/cls.py,sha256=7A0xGnugQzm8dOfnKMjLjtqekRlRtQ0jPFRYgq6xdUM,40018
@@ -30,8 +30,8 @@ modal/cls.pyi,sha256=_tZ5qrlL-ZDEcD-mf9BZkkNH5XPr4SmGTEQ-RVmqF3I,27772
30
30
  modal/config.py,sha256=FqVewLPVVR4feq_46JBENiCzqTuXKpnvQZxaeWbS39g,12009
31
31
  modal/container_process.py,sha256=XkPwNIW-iD_GB9u9yqv9q8y-i5cQ8eBbLZZ_GvEw9t8,6858
32
32
  modal/container_process.pyi,sha256=9m-st3hCUlNN1GOTctfPPvIvoLtEl7FbuGWwif5-7YU,6037
33
- modal/dict.py,sha256=YVrIARVfaD2kmdnqbGtneeLciiLkzKxYego0jfkv3Sk,14400
34
- modal/dict.pyi,sha256=gs3J7X5yG3J1L6rW0s3_7yRn8qAfY0f4n5-sqaDZY2g,20853
33
+ modal/dict.py,sha256=IyhKwQPM-HX10ZT-0ouSxpM-oAWqrT5waXFHmunmtyo,15804
34
+ modal/dict.pyi,sha256=vUrNmCKWZqiPIQSdbMT6fCq9q1QV3qkGVdz2B_yld34,22578
35
35
  modal/environments.py,sha256=gHFNLG78bqgizpQ4w_elz27QOqmcgAonFsmLs7NjUJ4,6804
36
36
  modal/environments.pyi,sha256=9-KtrzAcUe55cCP4020lSUD7-fWS7OPakAHssq4-bro,4219
37
37
  modal/exception.py,sha256=o0V93PK8Hcg2YQ2aeOB1Y-qWBw4Gz5ATfyokR8GapuQ,5634
@@ -50,7 +50,7 @@ modal/mount.pyi,sha256=n6AuS8J3bTCQj750nVZZdVBvzCAlSM2fyxAt_5LLFik,20264
50
50
  modal/network_file_system.py,sha256=AdjxI_hCYaDZz60gOuJeig8yourfWhHmEpn13C_fnMA,14775
51
51
  modal/network_file_system.pyi,sha256=Td_IobHr84iLo_9LZKQ4tNdUB60yjX8QWBaFiUvhfi8,17685
52
52
  modal/object.py,sha256=bTeskuY8JFrESjU4_UL_nTwYlBQdOLmVaOX3X6EMxsg,164
53
- modal/object.pyi,sha256=751TV6BntarPsErf0HDQPsvePjWFf0JZK8ZAiRpM1yg,6627
53
+ modal/object.pyi,sha256=sgbaq_d3QSmnPKg5jRbMG3dOceKs0l54kHUAhAyZKAE,6796
54
54
  modal/output.py,sha256=q4T9uHduunj4NwY-YSwkHGgjZlCXMuJbfQ5UFaAGRAc,1968
55
55
  modal/parallel_map.py,sha256=-9nS9s1jbx1Iqh_5HQRK4xTdhnXF4AGIXwT4UGJ8R78,52666
56
56
  modal/parallel_map.pyi,sha256=fCugFsGup4Cflesb10_uR-nt5_eguuvhvtvavus_F98,11186
@@ -59,8 +59,8 @@ modal/partial_function.pyi,sha256=lqqOzZ9-QvHTDWKQ_oAYYOvsXgTOBKhO9u-RI98JbUk,13
59
59
  modal/proxy.py,sha256=NQJJMGo-D2IfmeU0vb10WWaE4oTLcuf9jTeEJvactOg,1446
60
60
  modal/proxy.pyi,sha256=yWGWwADCRGrC2w81B7671UTH4Uv3HMZKy5vVqlJUZoA,1417
61
61
  modal/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
62
- modal/queue.py,sha256=LuOtO5s6Aes-oXgzmIfLvmEF-QtAZdC9LPqSRbqy-X0,18925
63
- modal/queue.pyi,sha256=J6ggmVodMRegDuJE0g7AmOPAoMKbgtfvlBrWaT-T7MA,26657
62
+ modal/queue.py,sha256=19Xri5HzY0VgOxWMZ4y_mNco8jhNgn9klegXrSHWmGc,20306
63
+ modal/queue.pyi,sha256=Pv4OtY7j17Yb89HGKaMQRiIv0yol-aV-ZtelxQ9GrlU,28330
64
64
  modal/retries.py,sha256=IvNLDM0f_GLUDD5VgEDoN09C88yoxSrCquinAuxT1Sc,5205
65
65
  modal/runner.py,sha256=ostdzYpQb-20tlD6dIq7bpWTkZkOhjJBNuMNektqnJA,24068
66
66
  modal/runner.pyi,sha256=lbwLljm1cC8d6PcNvmYQhkE8501V9fg0bYqqKX6G4r4,8489
@@ -69,8 +69,8 @@ modal/sandbox.py,sha256=_hAoBwParMzooNUo02LRt-nC5RrTGUtOutyO9oI79Kc,40896
69
69
  modal/sandbox.pyi,sha256=GPPlsm-DiSUSgrxyA5bqkpuLlrfgmNR7Z7s3W0QLuQ0,41812
70
70
  modal/schedule.py,sha256=ng0g0AqNY5GQI9KhkXZQ5Wam5G42glbkqVQsNpBtbDE,3078
71
71
  modal/scheduler_placement.py,sha256=BAREdOY5HzHpzSBqt6jDVR6YC_jYfHMVqOzkyqQfngU,1235
72
- modal/secret.py,sha256=rzqPd2kT1FoN_R1_nstso3ZLhkRf7iK-fRWhaUBwP6M,10577
73
- modal/secret.pyi,sha256=_d_vvgIZY-FCMKJheBOn01DQGEvyzB_Rfw5K1hGEaXU,7990
72
+ modal/secret.py,sha256=UaUmwYmT52VarDh92b0QzAa8_BNUAgBs-wE4eMQ6-B8,11967
73
+ modal/secret.pyi,sha256=zcC_OM0JzIF1ccnhNvVIlL6sY3xVjq3t0s3fE1ZDDVs,9732
74
74
  modal/serving.py,sha256=3I3WBeVbzZY258u9PXBCW_dZBgypq3OhwBuTVvlgubE,4423
75
75
  modal/serving.pyi,sha256=YfixTaWikyYpwhnNxCHMZnDDQiPmV1xJ87QF91U_WGU,1924
76
76
  modal/snapshot.py,sha256=E3oxYQkYVRB_LeFBfmUV1Y6vHz8-azXJfC4x7A1QKnI,1455
@@ -78,8 +78,8 @@ modal/snapshot.pyi,sha256=0q83hlmWxAhDu8xwZyL5VmYh0i8Tigf7S60or2k30L8,1682
78
78
  modal/stream_type.py,sha256=A6320qoAAWhEfwOCZfGtymQTu5AfLfJXXgARqooTPvY,417
79
79
  modal/token_flow.py,sha256=GWpar0gANs71vm9Bd_Cj87UG1K3ljTURbkEjG3JLsrY,7616
80
80
  modal/token_flow.pyi,sha256=eirYjyqbRiT3GCKMIPHJPpkvBTu8WxDKqSHehWaJI_4,2533
81
- modal/volume.py,sha256=aIGp_ZFD6UUqM2XnS19GBqWLc1_xOVBIx2JcFn30aYk,44475
82
- modal/volume.pyi,sha256=Qo5D0Bojcp8J4t4OoRArrBFaC1MSvFf9jQIL9U6Qz2Q,40779
81
+ modal/volume.py,sha256=b3VYD-0D8rZWxoeIIYpjqm2lgxrVOjFEgTyW2btUVnw,45396
82
+ modal/volume.pyi,sha256=lMXzeyeC85ji8g2j0Ghy1WQrk2A2J0LPVpLFpabbr6A,41933
83
83
  modal/_runtime/__init__.py,sha256=MIEP8jhXUeGq_eCjYFcqN5b1bxBM4fdk0VESpjWR0fc,28
84
84
  modal/_runtime/asgi.py,sha256=_2xSTsDD27Cit7xnMs4lzkJA2wzer2_N4Oa3BkXFzVA,22521
85
85
  modal/_runtime/container_io_manager.py,sha256=hjkK4gke_A8_mULSfm3F1hZKR0C61lKbRUI8mHS-LGE,45464
@@ -151,7 +151,7 @@ modal/experimental/__init__.py,sha256=nuc7AL4r_Fs08DD5dciWFZhrV1nanwoClOfdTcudU0
151
151
  modal/experimental/flash.py,sha256=7-_RBNvm0tEpdxXWuPAj5HCxfN-hSHVBep8SEWgAhCQ,19721
152
152
  modal/experimental/flash.pyi,sha256=A8_qJGtGoXEzKDdHbvhmCw7oqfneFEvJQK3ZdTOvUdU,10830
153
153
  modal/experimental/ipython.py,sha256=TrCfmol9LGsRZMeDoeMPx3Hv3BFqQhYnmD_iH0pqdhk,2904
154
- modal-1.1.1.dev26.dist-info/licenses/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
154
+ modal-1.1.1.dev28.dist-info/licenses/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
155
155
  modal_docs/__init__.py,sha256=svYKtV8HDwDCN86zbdWqyq5T8sMdGDj0PVlzc2tIxDM,28
156
156
  modal_docs/gen_cli_docs.py,sha256=c1yfBS_x--gL5bs0N4ihMwqwX8l3IBWSkBAKNNIi6bQ,3801
157
157
  modal_docs/gen_reference_docs.py,sha256=d_CQUGQ0rfw28u75I2mov9AlS773z9rG40-yq5o7g2U,6359
@@ -174,10 +174,10 @@ modal_proto/options_pb2.pyi,sha256=l7DBrbLO7q3Ir-XDkWsajm0d0TQqqrfuX54i4BMpdQg,1
174
174
  modal_proto/options_pb2_grpc.py,sha256=1oboBPFxaTEXt9Aw7EAj8gXHDCNMhZD2VXqocC9l_gk,159
175
175
  modal_proto/options_pb2_grpc.pyi,sha256=CImmhxHsYnF09iENPoe8S4J-n93jtgUYD2JPAc0yJSI,247
176
176
  modal_proto/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
177
- modal_version/__init__.py,sha256=nXGRSgHDLw-Aoa3Oy9TNto9xzwGo0zDk5GekIAscWs8,121
177
+ modal_version/__init__.py,sha256=Bhn-Ugb3ll-Q8THvxH35TRv5X0r0MdFbSqaPDwMQcxE,121
178
178
  modal_version/__main__.py,sha256=2FO0yYQQwDTh6udt1h-cBnGd1c4ZyHnHSI4BksxzVac,105
179
- modal-1.1.1.dev26.dist-info/METADATA,sha256=VcBI6MCCTq3s-owzZ580fF4dbDfBeNQNrezWiyZPLLU,2460
180
- modal-1.1.1.dev26.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
181
- modal-1.1.1.dev26.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
182
- modal-1.1.1.dev26.dist-info/top_level.txt,sha256=4BWzoKYREKUZ5iyPzZpjqx4G8uB5TWxXPDwibLcVa7k,43
183
- modal-1.1.1.dev26.dist-info/RECORD,,
179
+ modal-1.1.1.dev28.dist-info/METADATA,sha256=YXzS8Vb0BSQAE7bFDxldcOyJEBLClAY01vE9LMjpnZQ,2460
180
+ modal-1.1.1.dev28.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
181
+ modal-1.1.1.dev28.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
182
+ modal-1.1.1.dev28.dist-info/top_level.txt,sha256=4BWzoKYREKUZ5iyPzZpjqx4G8uB5TWxXPDwibLcVa7k,43
183
+ modal-1.1.1.dev28.dist-info/RECORD,,
modal_version/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
1
  # Copyright Modal Labs 2025
2
2
  """Supplies the current version of the modal client library."""
3
3
 
4
- __version__ = "1.1.1.dev26"
4
+ __version__ = "1.1.1.dev28"