modal 0.72.20__py3-none-any.whl → 0.72.22__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/_container_entrypoint.py +1 -1
- modal/_object.py +279 -0
- modal/_resolver.py +7 -5
- modal/_runtime/user_code_imports.py +7 -7
- modal/_serialization.py +4 -3
- modal/_tunnel.py +1 -1
- modal/app.py +1 -1
- modal/app.pyi +4 -3
- modal/cli/app.py +1 -1
- modal/cli/container.py +1 -1
- modal/client.py +1 -0
- modal/client.pyi +4 -2
- modal/cls.py +1 -1
- modal/cls.pyi +2 -1
- modal/dict.py +1 -1
- modal/dict.pyi +2 -1
- modal/environments.py +1 -1
- modal/environments.pyi +2 -1
- modal/functions.py +18 -20
- modal/functions.pyi +7 -6
- modal/image.py +16 -10
- modal/image.pyi +2 -1
- modal/mount.py +14 -5
- modal/mount.pyi +2 -1
- modal/network_file_system.py +7 -7
- modal/network_file_system.pyi +2 -1
- modal/object.py +2 -265
- modal/object.pyi +30 -122
- modal/proxy.py +1 -1
- modal/proxy.pyi +2 -1
- modal/queue.py +1 -1
- modal/queue.pyi +2 -1
- modal/runner.py +2 -2
- modal/sandbox.py +1 -1
- modal/sandbox.pyi +2 -1
- modal/secret.py +1 -1
- modal/secret.pyi +2 -1
- modal/volume.py +1 -1
- modal/volume.pyi +2 -1
- {modal-0.72.20.dist-info → modal-0.72.22.dist-info}/METADATA +1 -1
- {modal-0.72.20.dist-info → modal-0.72.22.dist-info}/RECORD +46 -45
- modal_version/_version_generated.py +1 -1
- {modal-0.72.20.dist-info → modal-0.72.22.dist-info}/LICENSE +0 -0
- {modal-0.72.20.dist-info → modal-0.72.22.dist-info}/WHEEL +0 -0
- {modal-0.72.20.dist-info → modal-0.72.22.dist-info}/entry_points.txt +0 -0
- {modal-0.72.20.dist-info → modal-0.72.22.dist-info}/top_level.txt +0 -0
modal/object.py
CHANGED
@@ -1,268 +1,5 @@
|
|
1
|
-
# Copyright Modal Labs
|
2
|
-
import
|
3
|
-
from collections.abc import Awaitable, Hashable, Sequence
|
4
|
-
from functools import wraps
|
5
|
-
from typing import Callable, ClassVar, Optional, TypeVar
|
6
|
-
|
7
|
-
from google.protobuf.message import Message
|
8
|
-
|
9
|
-
from modal._utils.async_utils import aclosing
|
10
|
-
|
11
|
-
from ._resolver import Resolver
|
1
|
+
# Copyright Modal Labs 2025
|
2
|
+
from ._object import _Object
|
12
3
|
from ._utils.async_utils import synchronize_api
|
13
|
-
from .client import _Client
|
14
|
-
from .config import config, logger
|
15
|
-
from .exception import ExecutionError, InvalidError
|
16
|
-
|
17
|
-
O = TypeVar("O", bound="_Object")
|
18
|
-
|
19
|
-
_BLOCKING_O = synchronize_api(O)
|
20
|
-
|
21
|
-
EPHEMERAL_OBJECT_HEARTBEAT_SLEEP: int = 300
|
22
|
-
|
23
|
-
|
24
|
-
def _get_environment_name(environment_name: Optional[str] = None, resolver: Optional[Resolver] = None) -> Optional[str]:
|
25
|
-
if environment_name:
|
26
|
-
return environment_name
|
27
|
-
elif resolver and resolver.environment_name:
|
28
|
-
return resolver.environment_name
|
29
|
-
else:
|
30
|
-
return config.get("environment")
|
31
|
-
|
32
|
-
|
33
|
-
class _Object:
|
34
|
-
_type_prefix: ClassVar[Optional[str]] = None
|
35
|
-
_prefix_to_type: ClassVar[dict[str, type]] = {}
|
36
|
-
|
37
|
-
# For constructors
|
38
|
-
_load: Optional[Callable[[O, Resolver, Optional[str]], Awaitable[None]]]
|
39
|
-
_preload: Optional[Callable[[O, Resolver, Optional[str]], Awaitable[None]]]
|
40
|
-
_rep: str
|
41
|
-
_is_another_app: bool
|
42
|
-
_hydrate_lazily: bool
|
43
|
-
_deps: Optional[Callable[..., list["_Object"]]]
|
44
|
-
_deduplication_key: Optional[Callable[[], Awaitable[Hashable]]] = None
|
45
|
-
|
46
|
-
# For hydrated objects
|
47
|
-
_object_id: str
|
48
|
-
_client: _Client
|
49
|
-
_is_hydrated: bool
|
50
|
-
_is_rehydrated: bool
|
51
|
-
|
52
|
-
@classmethod
|
53
|
-
def __init_subclass__(cls, type_prefix: Optional[str] = None):
|
54
|
-
super().__init_subclass__()
|
55
|
-
if type_prefix is not None:
|
56
|
-
cls._type_prefix = type_prefix
|
57
|
-
cls._prefix_to_type[type_prefix] = cls
|
58
|
-
|
59
|
-
def __init__(self, *args, **kwargs):
|
60
|
-
raise InvalidError(f"Class {type(self).__name__} has no constructor. Use class constructor methods instead.")
|
61
|
-
|
62
|
-
def _init(
|
63
|
-
self,
|
64
|
-
rep: str,
|
65
|
-
load: Optional[Callable[[O, Resolver, Optional[str]], Awaitable[None]]] = None,
|
66
|
-
is_another_app: bool = False,
|
67
|
-
preload: Optional[Callable[[O, Resolver, Optional[str]], Awaitable[None]]] = None,
|
68
|
-
hydrate_lazily: bool = False,
|
69
|
-
deps: Optional[Callable[..., list["_Object"]]] = None,
|
70
|
-
deduplication_key: Optional[Callable[[], Awaitable[Hashable]]] = None,
|
71
|
-
):
|
72
|
-
self._local_uuid = str(uuid.uuid4())
|
73
|
-
self._load = load
|
74
|
-
self._preload = preload
|
75
|
-
self._rep = rep
|
76
|
-
self._is_another_app = is_another_app
|
77
|
-
self._hydrate_lazily = hydrate_lazily
|
78
|
-
self._deps = deps
|
79
|
-
self._deduplication_key = deduplication_key
|
80
|
-
|
81
|
-
self._object_id = None
|
82
|
-
self._client = None
|
83
|
-
self._is_hydrated = False
|
84
|
-
self._is_rehydrated = False
|
85
|
-
|
86
|
-
self._initialize_from_empty()
|
87
|
-
|
88
|
-
def _unhydrate(self):
|
89
|
-
self._object_id = None
|
90
|
-
self._client = None
|
91
|
-
self._is_hydrated = False
|
92
|
-
|
93
|
-
def _initialize_from_empty(self):
|
94
|
-
# default implementation, can be overriden in subclasses
|
95
|
-
pass
|
96
|
-
|
97
|
-
def _initialize_from_other(self, other):
|
98
|
-
# default implementation, can be overriden in subclasses
|
99
|
-
self._object_id = other._object_id
|
100
|
-
self._is_hydrated = other._is_hydrated
|
101
|
-
self._client = other._client
|
102
|
-
|
103
|
-
def _hydrate(self, object_id: str, client: _Client, metadata: Optional[Message]):
|
104
|
-
assert isinstance(object_id, str)
|
105
|
-
if not object_id.startswith(self._type_prefix):
|
106
|
-
raise ExecutionError(
|
107
|
-
f"Can not hydrate {type(self)}:"
|
108
|
-
f" it has type prefix {self._type_prefix}"
|
109
|
-
f" but the object_id starts with {object_id[:3]}"
|
110
|
-
)
|
111
|
-
self._object_id = object_id
|
112
|
-
self._client = client
|
113
|
-
self._hydrate_metadata(metadata)
|
114
|
-
self._is_hydrated = True
|
115
|
-
|
116
|
-
def _hydrate_metadata(self, metadata: Optional[Message]):
|
117
|
-
# override this is subclasses that need additional data (other than an object_id) for a functioning Handle
|
118
|
-
pass
|
119
|
-
|
120
|
-
def _get_metadata(self) -> Optional[Message]:
|
121
|
-
# return the necessary metadata from this handle to be able to re-hydrate in another context if one is needed
|
122
|
-
# used to provide a handle's handle_metadata for serializing/pickling a live handle
|
123
|
-
# the object_id is already provided by other means
|
124
|
-
return
|
125
|
-
|
126
|
-
def _validate_is_hydrated(self: O):
|
127
|
-
if not self._is_hydrated:
|
128
|
-
object_type = self.__class__.__name__.strip("_")
|
129
|
-
if hasattr(self, "_app") and getattr(self._app, "_running_app", "") is None:
|
130
|
-
# The most common cause of this error: e.g., user called a Function without using App.run()
|
131
|
-
reason = ", because the App it is defined on is not running"
|
132
|
-
else:
|
133
|
-
# Technically possible, but with an ambiguous cause.
|
134
|
-
reason = ""
|
135
|
-
raise ExecutionError(
|
136
|
-
f"{object_type} has not been hydrated with the metadata it needs to run on Modal{reason}."
|
137
|
-
)
|
138
|
-
|
139
|
-
def clone(self: O) -> O:
|
140
|
-
"""mdmd:hidden Clone a given hydrated object."""
|
141
|
-
|
142
|
-
# Object to clone must already be hydrated, otherwise from_loader is more suitable.
|
143
|
-
self._validate_is_hydrated()
|
144
|
-
obj = type(self).__new__(type(self))
|
145
|
-
obj._initialize_from_other(self)
|
146
|
-
return obj
|
147
|
-
|
148
|
-
@classmethod
|
149
|
-
def _from_loader(
|
150
|
-
cls,
|
151
|
-
load: Callable[[O, Resolver, Optional[str]], Awaitable[None]],
|
152
|
-
rep: str,
|
153
|
-
is_another_app: bool = False,
|
154
|
-
preload: Optional[Callable[[O, Resolver, Optional[str]], Awaitable[None]]] = None,
|
155
|
-
hydrate_lazily: bool = False,
|
156
|
-
deps: Optional[Callable[..., Sequence["_Object"]]] = None,
|
157
|
-
deduplication_key: Optional[Callable[[], Awaitable[Hashable]]] = None,
|
158
|
-
):
|
159
|
-
# TODO(erikbern): flip the order of the two first arguments
|
160
|
-
obj = _Object.__new__(cls)
|
161
|
-
obj._init(rep, load, is_another_app, preload, hydrate_lazily, deps, deduplication_key)
|
162
|
-
return obj
|
163
|
-
|
164
|
-
@classmethod
|
165
|
-
def _get_type_from_id(cls: type[O], object_id: str) -> type[O]:
|
166
|
-
parts = object_id.split("-")
|
167
|
-
if len(parts) != 2:
|
168
|
-
raise InvalidError(f"Object id {object_id} has no dash in it")
|
169
|
-
prefix = parts[0]
|
170
|
-
if prefix not in cls._prefix_to_type:
|
171
|
-
raise InvalidError(f"Object prefix {prefix} does not correspond to a type")
|
172
|
-
return cls._prefix_to_type[prefix]
|
173
|
-
|
174
|
-
@classmethod
|
175
|
-
def _is_id_type(cls: type[O], object_id) -> bool:
|
176
|
-
return cls._get_type_from_id(object_id) == cls
|
177
|
-
|
178
|
-
@classmethod
|
179
|
-
def _new_hydrated(
|
180
|
-
cls: type[O], object_id: str, client: _Client, handle_metadata: Optional[Message], is_another_app: bool = False
|
181
|
-
) -> O:
|
182
|
-
if cls._type_prefix is not None:
|
183
|
-
# This is called directly on a subclass, e.g. Secret.from_id
|
184
|
-
if not object_id.startswith(cls._type_prefix + "-"):
|
185
|
-
raise InvalidError(f"Object {object_id} does not start with {cls._type_prefix}")
|
186
|
-
obj_cls = cls
|
187
|
-
else:
|
188
|
-
# This is called on the base class, e.g. Handle.from_id
|
189
|
-
obj_cls = cls._get_type_from_id(object_id)
|
190
|
-
|
191
|
-
# Instantiate provider
|
192
|
-
obj = _Object.__new__(obj_cls)
|
193
|
-
rep = f"Object({object_id})" # TODO(erikbern): dumb
|
194
|
-
obj._init(rep, is_another_app=is_another_app)
|
195
|
-
obj._hydrate(object_id, client, handle_metadata)
|
196
|
-
|
197
|
-
return obj
|
198
|
-
|
199
|
-
def _hydrate_from_other(self, other: O):
|
200
|
-
self._hydrate(other._object_id, other._client, other._get_metadata())
|
201
|
-
|
202
|
-
def __repr__(self):
|
203
|
-
return self._rep
|
204
|
-
|
205
|
-
@property
|
206
|
-
def local_uuid(self):
|
207
|
-
"""mdmd:hidden"""
|
208
|
-
return self._local_uuid
|
209
|
-
|
210
|
-
@property
|
211
|
-
def object_id(self) -> str:
|
212
|
-
"""mdmd:hidden"""
|
213
|
-
return self._object_id
|
214
|
-
|
215
|
-
@property
|
216
|
-
def is_hydrated(self) -> bool:
|
217
|
-
"""mdmd:hidden"""
|
218
|
-
return self._is_hydrated
|
219
|
-
|
220
|
-
@property
|
221
|
-
def deps(self) -> Callable[..., list["_Object"]]:
|
222
|
-
"""mdmd:hidden"""
|
223
|
-
return self._deps if self._deps is not None else lambda: []
|
224
|
-
|
225
|
-
async def resolve(self, client: Optional[_Client] = None):
|
226
|
-
"""mdmd:hidden"""
|
227
|
-
if self._is_hydrated:
|
228
|
-
# memory snapshots capture references which must be rehydrated
|
229
|
-
# on restore to handle staleness.
|
230
|
-
if self._client._snapshotted and not self._is_rehydrated:
|
231
|
-
logger.debug(f"rehydrating {self} after snapshot")
|
232
|
-
self._is_hydrated = False # un-hydrate and re-resolve
|
233
|
-
c = client if client is not None else await _Client.from_env()
|
234
|
-
resolver = Resolver(c)
|
235
|
-
await resolver.load(self)
|
236
|
-
self._is_rehydrated = True
|
237
|
-
logger.debug(f"rehydrated {self} with client {id(c)}")
|
238
|
-
return
|
239
|
-
elif not self._hydrate_lazily:
|
240
|
-
self._validate_is_hydrated()
|
241
|
-
else:
|
242
|
-
# TODO: this client and/or resolver can't be changed by a caller to X.from_name()
|
243
|
-
c = client if client is not None else await _Client.from_env()
|
244
|
-
resolver = Resolver(c)
|
245
|
-
await resolver.load(self)
|
246
|
-
|
247
4
|
|
248
5
|
Object = synchronize_api(_Object, target_module=__name__)
|
249
|
-
|
250
|
-
|
251
|
-
def live_method(method):
|
252
|
-
@wraps(method)
|
253
|
-
async def wrapped(self, *args, **kwargs):
|
254
|
-
await self.resolve()
|
255
|
-
return await method(self, *args, **kwargs)
|
256
|
-
|
257
|
-
return wrapped
|
258
|
-
|
259
|
-
|
260
|
-
def live_method_gen(method):
|
261
|
-
@wraps(method)
|
262
|
-
async def wrapped(self, *args, **kwargs):
|
263
|
-
await self.resolve()
|
264
|
-
async with aclosing(method(self, *args, **kwargs)) as stream:
|
265
|
-
async for item in stream:
|
266
|
-
yield item
|
267
|
-
|
268
|
-
return wrapped
|
modal/object.pyi
CHANGED
@@ -5,117 +5,26 @@ import modal.client
|
|
5
5
|
import typing
|
6
6
|
import typing_extensions
|
7
7
|
|
8
|
-
O = typing.TypeVar("O", bound="_Object")
|
9
|
-
|
10
|
-
_BLOCKING_O = typing.TypeVar("_BLOCKING_O", bound="Object")
|
11
|
-
|
12
|
-
def _get_environment_name(
|
13
|
-
environment_name: typing.Optional[str] = None, resolver: typing.Optional[modal._resolver.Resolver] = None
|
14
|
-
) -> typing.Optional[str]: ...
|
15
|
-
|
16
|
-
class _Object:
|
17
|
-
_type_prefix: typing.ClassVar[typing.Optional[str]]
|
18
|
-
_prefix_to_type: typing.ClassVar[dict[str, type]]
|
19
|
-
_load: typing.Optional[
|
20
|
-
typing.Callable[[O, modal._resolver.Resolver, typing.Optional[str]], collections.abc.Awaitable[None]]
|
21
|
-
]
|
22
|
-
_preload: typing.Optional[
|
23
|
-
typing.Callable[[O, modal._resolver.Resolver, typing.Optional[str]], collections.abc.Awaitable[None]]
|
24
|
-
]
|
25
|
-
_rep: str
|
26
|
-
_is_another_app: bool
|
27
|
-
_hydrate_lazily: bool
|
28
|
-
_deps: typing.Optional[typing.Callable[..., list[_Object]]]
|
29
|
-
_deduplication_key: typing.Optional[typing.Callable[[], collections.abc.Awaitable[collections.abc.Hashable]]]
|
30
|
-
_object_id: str
|
31
|
-
_client: modal.client._Client
|
32
|
-
_is_hydrated: bool
|
33
|
-
_is_rehydrated: bool
|
34
|
-
|
35
|
-
@classmethod
|
36
|
-
def __init_subclass__(cls, type_prefix: typing.Optional[str] = None): ...
|
37
|
-
def __init__(self, *args, **kwargs): ...
|
38
|
-
def _init(
|
39
|
-
self,
|
40
|
-
rep: str,
|
41
|
-
load: typing.Optional[
|
42
|
-
typing.Callable[[O, modal._resolver.Resolver, typing.Optional[str]], collections.abc.Awaitable[None]]
|
43
|
-
] = None,
|
44
|
-
is_another_app: bool = False,
|
45
|
-
preload: typing.Optional[
|
46
|
-
typing.Callable[[O, modal._resolver.Resolver, typing.Optional[str]], collections.abc.Awaitable[None]]
|
47
|
-
] = None,
|
48
|
-
hydrate_lazily: bool = False,
|
49
|
-
deps: typing.Optional[typing.Callable[..., list[_Object]]] = None,
|
50
|
-
deduplication_key: typing.Optional[
|
51
|
-
typing.Callable[[], collections.abc.Awaitable[collections.abc.Hashable]]
|
52
|
-
] = None,
|
53
|
-
): ...
|
54
|
-
def _unhydrate(self): ...
|
55
|
-
def _initialize_from_empty(self): ...
|
56
|
-
def _initialize_from_other(self, other): ...
|
57
|
-
def _hydrate(
|
58
|
-
self, object_id: str, client: modal.client._Client, metadata: typing.Optional[google.protobuf.message.Message]
|
59
|
-
): ...
|
60
|
-
def _hydrate_metadata(self, metadata: typing.Optional[google.protobuf.message.Message]): ...
|
61
|
-
def _get_metadata(self) -> typing.Optional[google.protobuf.message.Message]: ...
|
62
|
-
def _validate_is_hydrated(self: O): ...
|
63
|
-
def clone(self: O) -> O: ...
|
64
|
-
@classmethod
|
65
|
-
def _from_loader(
|
66
|
-
cls,
|
67
|
-
load: typing.Callable[[O, modal._resolver.Resolver, typing.Optional[str]], collections.abc.Awaitable[None]],
|
68
|
-
rep: str,
|
69
|
-
is_another_app: bool = False,
|
70
|
-
preload: typing.Optional[
|
71
|
-
typing.Callable[[O, modal._resolver.Resolver, typing.Optional[str]], collections.abc.Awaitable[None]]
|
72
|
-
] = None,
|
73
|
-
hydrate_lazily: bool = False,
|
74
|
-
deps: typing.Optional[typing.Callable[..., collections.abc.Sequence[_Object]]] = None,
|
75
|
-
deduplication_key: typing.Optional[
|
76
|
-
typing.Callable[[], collections.abc.Awaitable[collections.abc.Hashable]]
|
77
|
-
] = None,
|
78
|
-
): ...
|
79
|
-
@classmethod
|
80
|
-
def _get_type_from_id(cls: type[O], object_id: str) -> type[O]: ...
|
81
|
-
@classmethod
|
82
|
-
def _is_id_type(cls: type[O], object_id) -> bool: ...
|
83
|
-
@classmethod
|
84
|
-
def _new_hydrated(
|
85
|
-
cls: type[O],
|
86
|
-
object_id: str,
|
87
|
-
client: modal.client._Client,
|
88
|
-
handle_metadata: typing.Optional[google.protobuf.message.Message],
|
89
|
-
is_another_app: bool = False,
|
90
|
-
) -> O: ...
|
91
|
-
def _hydrate_from_other(self, other: O): ...
|
92
|
-
def __repr__(self): ...
|
93
|
-
@property
|
94
|
-
def local_uuid(self): ...
|
95
|
-
@property
|
96
|
-
def object_id(self) -> str: ...
|
97
|
-
@property
|
98
|
-
def is_hydrated(self) -> bool: ...
|
99
|
-
@property
|
100
|
-
def deps(self) -> typing.Callable[..., list[_Object]]: ...
|
101
|
-
async def resolve(self, client: typing.Optional[modal.client._Client] = None): ...
|
102
|
-
|
103
8
|
class Object:
|
104
9
|
_type_prefix: typing.ClassVar[typing.Optional[str]]
|
105
10
|
_prefix_to_type: typing.ClassVar[dict[str, type]]
|
106
11
|
_load: typing.Optional[
|
107
|
-
typing.Callable[
|
12
|
+
typing.Callable[
|
13
|
+
[typing_extensions.Self, modal._resolver.Resolver, typing.Optional[str]], collections.abc.Awaitable[None]
|
14
|
+
]
|
108
15
|
]
|
109
16
|
_preload: typing.Optional[
|
110
|
-
typing.Callable[
|
17
|
+
typing.Callable[
|
18
|
+
[typing_extensions.Self, modal._resolver.Resolver, typing.Optional[str]], collections.abc.Awaitable[None]
|
19
|
+
]
|
111
20
|
]
|
112
21
|
_rep: str
|
113
22
|
_is_another_app: bool
|
114
23
|
_hydrate_lazily: bool
|
115
|
-
_deps: typing.Optional[typing.Callable[...,
|
24
|
+
_deps: typing.Optional[typing.Callable[..., collections.abc.Sequence[Object]]]
|
116
25
|
_deduplication_key: typing.Optional[typing.Callable[[], collections.abc.Awaitable[collections.abc.Hashable]]]
|
117
|
-
_object_id: str
|
118
|
-
_client: modal.client.Client
|
26
|
+
_object_id: typing.Optional[str]
|
27
|
+
_client: typing.Optional[modal.client.Client]
|
119
28
|
_is_hydrated: bool
|
120
29
|
_is_rehydrated: bool
|
121
30
|
|
@@ -128,14 +37,14 @@ class Object:
|
|
128
37
|
self,
|
129
38
|
rep: str,
|
130
39
|
load: typing.Optional[
|
131
|
-
typing.Callable[[
|
40
|
+
typing.Callable[[typing_extensions.Self, modal._resolver.Resolver, typing.Optional[str]], None]
|
132
41
|
] = None,
|
133
42
|
is_another_app: bool = False,
|
134
43
|
preload: typing.Optional[
|
135
|
-
typing.Callable[[
|
44
|
+
typing.Callable[[typing_extensions.Self, modal._resolver.Resolver, typing.Optional[str]], None]
|
136
45
|
] = None,
|
137
46
|
hydrate_lazily: bool = False,
|
138
|
-
deps: typing.Optional[typing.Callable[...,
|
47
|
+
deps: typing.Optional[typing.Callable[..., collections.abc.Sequence[Object]]] = None,
|
139
48
|
deduplication_key: typing.Optional[typing.Callable[[], collections.abc.Hashable]] = None,
|
140
49
|
): ...
|
141
50
|
def aio(
|
@@ -143,17 +52,19 @@ class Object:
|
|
143
52
|
rep: str,
|
144
53
|
load: typing.Optional[
|
145
54
|
typing.Callable[
|
146
|
-
[
|
55
|
+
[typing_extensions.Self, modal._resolver.Resolver, typing.Optional[str]],
|
56
|
+
collections.abc.Awaitable[None],
|
147
57
|
]
|
148
58
|
] = None,
|
149
59
|
is_another_app: bool = False,
|
150
60
|
preload: typing.Optional[
|
151
61
|
typing.Callable[
|
152
|
-
[
|
62
|
+
[typing_extensions.Self, modal._resolver.Resolver, typing.Optional[str]],
|
63
|
+
collections.abc.Awaitable[None],
|
153
64
|
]
|
154
65
|
] = None,
|
155
66
|
hydrate_lazily: bool = False,
|
156
|
-
deps: typing.Optional[typing.Callable[...,
|
67
|
+
deps: typing.Optional[typing.Callable[..., collections.abc.Sequence[Object]]] = None,
|
157
68
|
deduplication_key: typing.Optional[
|
158
69
|
typing.Callable[[], collections.abc.Awaitable[collections.abc.Hashable]]
|
159
70
|
] = None,
|
@@ -169,51 +80,48 @@ class Object:
|
|
169
80
|
): ...
|
170
81
|
def _hydrate_metadata(self, metadata: typing.Optional[google.protobuf.message.Message]): ...
|
171
82
|
def _get_metadata(self) -> typing.Optional[google.protobuf.message.Message]: ...
|
172
|
-
def _validate_is_hydrated(self
|
173
|
-
def clone(self
|
83
|
+
def _validate_is_hydrated(self): ...
|
84
|
+
def clone(self) -> typing_extensions.Self: ...
|
174
85
|
@classmethod
|
175
86
|
def _from_loader(
|
176
87
|
cls,
|
177
|
-
load: typing.Callable[[
|
88
|
+
load: typing.Callable[[typing_extensions.Self, modal._resolver.Resolver, typing.Optional[str]], None],
|
178
89
|
rep: str,
|
179
90
|
is_another_app: bool = False,
|
180
91
|
preload: typing.Optional[
|
181
|
-
typing.Callable[[
|
92
|
+
typing.Callable[[typing_extensions.Self, modal._resolver.Resolver, typing.Optional[str]], None]
|
182
93
|
] = None,
|
183
94
|
hydrate_lazily: bool = False,
|
184
95
|
deps: typing.Optional[typing.Callable[..., collections.abc.Sequence[Object]]] = None,
|
185
96
|
deduplication_key: typing.Optional[typing.Callable[[], collections.abc.Hashable]] = None,
|
186
97
|
): ...
|
98
|
+
@staticmethod
|
99
|
+
def _get_type_from_id(object_id: str) -> type[Object]: ...
|
187
100
|
@classmethod
|
188
|
-
def
|
189
|
-
@classmethod
|
190
|
-
def _is_id_type(cls: type[_BLOCKING_O], object_id) -> bool: ...
|
101
|
+
def _is_id_type(cls, object_id) -> bool: ...
|
191
102
|
@classmethod
|
192
103
|
def _new_hydrated(
|
193
|
-
cls
|
104
|
+
cls,
|
194
105
|
object_id: str,
|
195
106
|
client: modal.client.Client,
|
196
107
|
handle_metadata: typing.Optional[google.protobuf.message.Message],
|
197
108
|
is_another_app: bool = False,
|
198
|
-
) ->
|
199
|
-
def _hydrate_from_other(self, other:
|
109
|
+
) -> typing_extensions.Self: ...
|
110
|
+
def _hydrate_from_other(self, other: typing_extensions.Self): ...
|
200
111
|
def __repr__(self): ...
|
201
112
|
@property
|
202
113
|
def local_uuid(self): ...
|
203
114
|
@property
|
204
115
|
def object_id(self) -> str: ...
|
205
116
|
@property
|
117
|
+
def client(self) -> modal.client.Client: ...
|
118
|
+
@property
|
206
119
|
def is_hydrated(self) -> bool: ...
|
207
120
|
@property
|
208
|
-
def deps(self) -> typing.Callable[...,
|
121
|
+
def deps(self) -> typing.Callable[..., collections.abc.Sequence[Object]]: ...
|
209
122
|
|
210
123
|
class __resolve_spec(typing_extensions.Protocol):
|
211
124
|
def __call__(self, client: typing.Optional[modal.client.Client] = None): ...
|
212
125
|
async def aio(self, client: typing.Optional[modal.client.Client] = None): ...
|
213
126
|
|
214
127
|
resolve: __resolve_spec
|
215
|
-
|
216
|
-
def live_method(method): ...
|
217
|
-
def live_method_gen(method): ...
|
218
|
-
|
219
|
-
EPHEMERAL_OBJECT_HEARTBEAT_SLEEP: int
|
modal/proxy.py
CHANGED
@@ -3,9 +3,9 @@ from typing import Optional
|
|
3
3
|
|
4
4
|
from modal_proto import api_pb2
|
5
5
|
|
6
|
+
from ._object import _get_environment_name, _Object
|
6
7
|
from ._resolver import Resolver
|
7
8
|
from ._utils.async_utils import synchronize_api
|
8
|
-
from .object import _get_environment_name, _Object
|
9
9
|
|
10
10
|
|
11
11
|
class _Proxy(_Object, type_prefix="pr"):
|
modal/proxy.pyi
CHANGED
modal/queue.py
CHANGED
@@ -10,6 +10,7 @@ from synchronicity.async_wrap import asynccontextmanager
|
|
10
10
|
|
11
11
|
from modal_proto import api_pb2
|
12
12
|
|
13
|
+
from ._object import EPHEMERAL_OBJECT_HEARTBEAT_SLEEP, _get_environment_name, _Object, live_method, live_method_gen
|
13
14
|
from ._resolver import Resolver
|
14
15
|
from ._serialization import deserialize, serialize
|
15
16
|
from ._utils.async_utils import TaskContext, synchronize_api, warn_if_generator_is_not_consumed
|
@@ -18,7 +19,6 @@ from ._utils.grpc_utils import retry_transient_errors
|
|
18
19
|
from ._utils.name_utils import check_object_name
|
19
20
|
from .client import _Client
|
20
21
|
from .exception import InvalidError, RequestSizeError
|
21
|
-
from .object import EPHEMERAL_OBJECT_HEARTBEAT_SLEEP, _get_environment_name, _Object, live_method, live_method_gen
|
22
22
|
|
23
23
|
|
24
24
|
class _Queue(_Object, type_prefix="qu"):
|
modal/queue.pyi
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
import collections.abc
|
2
|
+
import modal._object
|
2
3
|
import modal.client
|
3
4
|
import modal.object
|
4
5
|
import synchronicity.combined_types
|
5
6
|
import typing
|
6
7
|
import typing_extensions
|
7
8
|
|
8
|
-
class _Queue(modal.
|
9
|
+
class _Queue(modal._object._Object):
|
9
10
|
def __init__(self): ...
|
10
11
|
@staticmethod
|
11
12
|
def validate_partition_key(partition: typing.Optional[str]) -> bytes: ...
|
modal/runner.py
CHANGED
@@ -14,6 +14,7 @@ from synchronicity.async_wrap import asynccontextmanager
|
|
14
14
|
import modal_proto.api_pb2
|
15
15
|
from modal_proto import api_pb2
|
16
16
|
|
17
|
+
from ._object import _get_environment_name, _Object
|
17
18
|
from ._pty import get_pty_info
|
18
19
|
from ._resolver import Resolver
|
19
20
|
from ._runtime.execution_context import is_local
|
@@ -28,7 +29,6 @@ from .config import config, logger
|
|
28
29
|
from .environments import _get_environment_cached
|
29
30
|
from .exception import InteractiveTimeoutError, InvalidError, RemoteError, _CliUserExecutionError
|
30
31
|
from .functions import _Function
|
31
|
-
from .object import _get_environment_name, _Object
|
32
32
|
from .output import _get_output_manager, enable_output
|
33
33
|
from .running_app import RunningApp, running_app_from_layout
|
34
34
|
from .sandbox import _Sandbox
|
@@ -155,7 +155,7 @@ async def _create_all_objects(
|
|
155
155
|
# this is to ensure that directly referenced functions from the global scope has
|
156
156
|
# ids associated with them when they are serialized into other functions
|
157
157
|
await resolver.preload(obj, existing_object_id)
|
158
|
-
if obj.
|
158
|
+
if obj.is_hydrated:
|
159
159
|
tag_to_object_id[tag] = obj.object_id
|
160
160
|
|
161
161
|
await TaskContext.gather(*(_preload(tag, obj) for tag, obj in indexed_objects.items()))
|
modal/sandbox.py
CHANGED
@@ -16,6 +16,7 @@ from modal.volume import _Volume
|
|
16
16
|
from modal_proto import api_pb2
|
17
17
|
|
18
18
|
from ._location import parse_cloud_provider
|
19
|
+
from ._object import _get_environment_name, _Object
|
19
20
|
from ._resolver import Resolver
|
20
21
|
from ._resources import convert_fn_config_to_resources_config
|
21
22
|
from ._utils.async_utils import synchronize_api
|
@@ -32,7 +33,6 @@ from .image import _Image
|
|
32
33
|
from .io_streams import StreamReader, StreamWriter, _StreamReader, _StreamWriter
|
33
34
|
from .mount import _Mount
|
34
35
|
from .network_file_system import _NetworkFileSystem, network_file_system_mount_protos
|
35
|
-
from .object import _get_environment_name, _Object
|
36
36
|
from .proxy import _Proxy
|
37
37
|
from .scheduler_placement import SchedulerPlacement
|
38
38
|
from .secret import _Secret
|
modal/sandbox.pyi
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
import _typeshed
|
2
2
|
import collections.abc
|
3
3
|
import google.protobuf.message
|
4
|
+
import modal._object
|
4
5
|
import modal._tunnel
|
5
6
|
import modal.app
|
6
7
|
import modal.client
|
@@ -23,7 +24,7 @@ import os
|
|
23
24
|
import typing
|
24
25
|
import typing_extensions
|
25
26
|
|
26
|
-
class _Sandbox(modal.
|
27
|
+
class _Sandbox(modal._object._Object):
|
27
28
|
_result: typing.Optional[modal_proto.api_pb2.GenericResult]
|
28
29
|
_stdout: modal.io_streams._StreamReader[str]
|
29
30
|
_stderr: modal.io_streams._StreamReader[str]
|
modal/secret.py
CHANGED
@@ -6,6 +6,7 @@ from grpclib import GRPCError, Status
|
|
6
6
|
|
7
7
|
from modal_proto import api_pb2
|
8
8
|
|
9
|
+
from ._object import _get_environment_name, _Object
|
9
10
|
from ._resolver import Resolver
|
10
11
|
from ._runtime.execution_context import is_local
|
11
12
|
from ._utils.async_utils import synchronize_api
|
@@ -14,7 +15,6 @@ from ._utils.grpc_utils import retry_transient_errors
|
|
14
15
|
from ._utils.name_utils import check_object_name
|
15
16
|
from .client import _Client
|
16
17
|
from .exception import InvalidError, NotFoundError
|
17
|
-
from .object import _get_environment_name, _Object
|
18
18
|
|
19
19
|
ENV_DICT_WRONG_TYPE_ERR = "the env_dict argument to Secret has to be a dict[str, Union[str, None]]"
|
20
20
|
|
modal/secret.pyi
CHANGED
@@ -1,9 +1,10 @@
|
|
1
|
+
import modal._object
|
1
2
|
import modal.client
|
2
3
|
import modal.object
|
3
4
|
import typing
|
4
5
|
import typing_extensions
|
5
6
|
|
6
|
-
class _Secret(modal.
|
7
|
+
class _Secret(modal._object._Object):
|
7
8
|
@staticmethod
|
8
9
|
def from_dict(env_dict: dict[str, typing.Optional[str]] = {}): ...
|
9
10
|
@staticmethod
|
modal/volume.py
CHANGED
@@ -27,6 +27,7 @@ import modal_proto.api_pb2
|
|
27
27
|
from modal.exception import VolumeUploadTimeoutError
|
28
28
|
from modal_proto import api_pb2
|
29
29
|
|
30
|
+
from ._object import EPHEMERAL_OBJECT_HEARTBEAT_SLEEP, _get_environment_name, _Object, live_method, live_method_gen
|
30
31
|
from ._resolver import Resolver
|
31
32
|
from ._utils.async_utils import TaskContext, aclosing, async_map, asyncnullcontext, synchronize_api
|
32
33
|
from ._utils.blob_utils import (
|
@@ -41,7 +42,6 @@ from ._utils.grpc_utils import retry_transient_errors
|
|
41
42
|
from ._utils.name_utils import check_object_name
|
42
43
|
from .client import _Client
|
43
44
|
from .config import logger
|
44
|
-
from .object import EPHEMERAL_OBJECT_HEARTBEAT_SLEEP, _get_environment_name, _Object, live_method, live_method_gen
|
45
45
|
|
46
46
|
# Max duration for uploading to volumes files
|
47
47
|
# As a guide, files >40GiB will take >10 minutes to upload.
|
modal/volume.pyi
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
import asyncio.locks
|
2
2
|
import collections.abc
|
3
3
|
import enum
|
4
|
+
import modal._object
|
4
5
|
import modal._utils.blob_utils
|
5
6
|
import modal.client
|
6
7
|
import modal.object
|
@@ -33,7 +34,7 @@ class FileEntry:
|
|
33
34
|
def __delattr__(self, name): ...
|
34
35
|
def __hash__(self): ...
|
35
36
|
|
36
|
-
class _Volume(modal.
|
37
|
+
class _Volume(modal._object._Object):
|
37
38
|
_lock: typing.Optional[asyncio.locks.Lock]
|
38
39
|
|
39
40
|
async def _get_lock(self): ...
|