modal 0.72.21__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/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 +13 -12
- modal/image.py +6 -6
- modal/image.pyi +2 -1
- modal/mount.py +1 -1
- 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.21.dist-info → modal-0.72.22.dist-info}/METADATA +1 -1
- {modal-0.72.21.dist-info → modal-0.72.22.dist-info}/RECORD +45 -44
- modal_version/_version_generated.py +1 -1
- {modal-0.72.21.dist-info → modal-0.72.22.dist-info}/LICENSE +0 -0
- {modal-0.72.21.dist-info → modal-0.72.22.dist-info}/WHEEL +0 -0
- {modal-0.72.21.dist-info → modal-0.72.22.dist-info}/entry_points.txt +0 -0
- {modal-0.72.21.dist-info → modal-0.72.22.dist-info}/top_level.txt +0 -0
modal/_container_entrypoint.py
CHANGED
@@ -50,8 +50,8 @@ from ._runtime.container_io_manager import (
|
|
50
50
|
from ._runtime.execution_context import _set_current_context_ids
|
51
51
|
|
52
52
|
if TYPE_CHECKING:
|
53
|
+
import modal._object
|
53
54
|
import modal._runtime.container_io_manager
|
54
|
-
import modal.object
|
55
55
|
|
56
56
|
|
57
57
|
class DaemonizedThreadPool:
|
modal/_object.py
ADDED
@@ -0,0 +1,279 @@
|
|
1
|
+
# Copyright Modal Labs 2022
|
2
|
+
import typing
|
3
|
+
import uuid
|
4
|
+
from collections.abc import Awaitable, Hashable, Sequence
|
5
|
+
from functools import wraps
|
6
|
+
from typing import Callable, ClassVar, Optional
|
7
|
+
|
8
|
+
from google.protobuf.message import Message
|
9
|
+
from typing_extensions import Self
|
10
|
+
|
11
|
+
from modal._utils.async_utils import aclosing
|
12
|
+
|
13
|
+
from ._resolver import Resolver
|
14
|
+
from .client import _Client
|
15
|
+
from .config import config, logger
|
16
|
+
from .exception import ExecutionError, InvalidError
|
17
|
+
|
18
|
+
EPHEMERAL_OBJECT_HEARTBEAT_SLEEP: int = 300
|
19
|
+
|
20
|
+
|
21
|
+
def _get_environment_name(environment_name: Optional[str] = None, resolver: Optional[Resolver] = None) -> Optional[str]:
|
22
|
+
if environment_name:
|
23
|
+
return environment_name
|
24
|
+
elif resolver and resolver.environment_name:
|
25
|
+
return resolver.environment_name
|
26
|
+
else:
|
27
|
+
return config.get("environment")
|
28
|
+
|
29
|
+
|
30
|
+
class _Object:
|
31
|
+
_type_prefix: ClassVar[Optional[str]] = None
|
32
|
+
_prefix_to_type: ClassVar[dict[str, type]] = {}
|
33
|
+
|
34
|
+
# For constructors
|
35
|
+
_load: Optional[Callable[[Self, Resolver, Optional[str]], Awaitable[None]]]
|
36
|
+
_preload: Optional[Callable[[Self, Resolver, Optional[str]], Awaitable[None]]]
|
37
|
+
_rep: str
|
38
|
+
_is_another_app: bool
|
39
|
+
_hydrate_lazily: bool
|
40
|
+
_deps: Optional[Callable[..., Sequence["_Object"]]]
|
41
|
+
_deduplication_key: Optional[Callable[[], Awaitable[Hashable]]] = None
|
42
|
+
|
43
|
+
# For hydrated objects
|
44
|
+
_object_id: Optional[str]
|
45
|
+
_client: Optional[_Client]
|
46
|
+
_is_hydrated: bool
|
47
|
+
_is_rehydrated: bool
|
48
|
+
|
49
|
+
@classmethod
|
50
|
+
def __init_subclass__(cls, type_prefix: Optional[str] = None):
|
51
|
+
super().__init_subclass__()
|
52
|
+
if type_prefix is not None:
|
53
|
+
cls._type_prefix = type_prefix
|
54
|
+
cls._prefix_to_type[type_prefix] = cls
|
55
|
+
|
56
|
+
def __init__(self, *args, **kwargs):
|
57
|
+
raise InvalidError(f"Class {type(self).__name__} has no constructor. Use class constructor methods instead.")
|
58
|
+
|
59
|
+
def _init(
|
60
|
+
self,
|
61
|
+
rep: str,
|
62
|
+
load: Optional[Callable[[Self, Resolver, Optional[str]], Awaitable[None]]] = None,
|
63
|
+
is_another_app: bool = False,
|
64
|
+
preload: Optional[Callable[[Self, Resolver, Optional[str]], Awaitable[None]]] = None,
|
65
|
+
hydrate_lazily: bool = False,
|
66
|
+
deps: Optional[Callable[..., Sequence["_Object"]]] = None,
|
67
|
+
deduplication_key: Optional[Callable[[], Awaitable[Hashable]]] = None,
|
68
|
+
):
|
69
|
+
self._local_uuid = str(uuid.uuid4())
|
70
|
+
self._load = load
|
71
|
+
self._preload = preload
|
72
|
+
self._rep = rep
|
73
|
+
self._is_another_app = is_another_app
|
74
|
+
self._hydrate_lazily = hydrate_lazily
|
75
|
+
self._deps = deps
|
76
|
+
self._deduplication_key = deduplication_key
|
77
|
+
|
78
|
+
self._object_id = None
|
79
|
+
self._client = None
|
80
|
+
self._is_hydrated = False
|
81
|
+
self._is_rehydrated = False
|
82
|
+
|
83
|
+
self._initialize_from_empty()
|
84
|
+
|
85
|
+
def _unhydrate(self):
|
86
|
+
self._object_id = None
|
87
|
+
self._client = None
|
88
|
+
self._is_hydrated = False
|
89
|
+
|
90
|
+
def _initialize_from_empty(self):
|
91
|
+
# default implementation, can be overriden in subclasses
|
92
|
+
pass
|
93
|
+
|
94
|
+
def _initialize_from_other(self, other):
|
95
|
+
# default implementation, can be overriden in subclasses
|
96
|
+
self._object_id = other._object_id
|
97
|
+
self._is_hydrated = other._is_hydrated
|
98
|
+
self._client = other._client
|
99
|
+
|
100
|
+
def _hydrate(self, object_id: str, client: _Client, metadata: Optional[Message]):
|
101
|
+
assert isinstance(object_id, str) and self._type_prefix is not None
|
102
|
+
if not object_id.startswith(self._type_prefix):
|
103
|
+
raise ExecutionError(
|
104
|
+
f"Can not hydrate {type(self)}:"
|
105
|
+
f" it has type prefix {self._type_prefix}"
|
106
|
+
f" but the object_id starts with {object_id[:3]}"
|
107
|
+
)
|
108
|
+
self._object_id = object_id
|
109
|
+
self._client = client
|
110
|
+
self._hydrate_metadata(metadata)
|
111
|
+
self._is_hydrated = True
|
112
|
+
|
113
|
+
def _hydrate_metadata(self, metadata: Optional[Message]):
|
114
|
+
# override this is subclasses that need additional data (other than an object_id) for a functioning Handle
|
115
|
+
pass
|
116
|
+
|
117
|
+
def _get_metadata(self) -> Optional[Message]:
|
118
|
+
# return the necessary metadata from this handle to be able to re-hydrate in another context if one is needed
|
119
|
+
# used to provide a handle's handle_metadata for serializing/pickling a live handle
|
120
|
+
# the object_id is already provided by other means
|
121
|
+
return None
|
122
|
+
|
123
|
+
def _validate_is_hydrated(self):
|
124
|
+
if not self._is_hydrated:
|
125
|
+
object_type = self.__class__.__name__.strip("_")
|
126
|
+
if hasattr(self, "_app") and getattr(self._app, "_running_app", "") is None: # type: ignore
|
127
|
+
# The most common cause of this error: e.g., user called a Function without using App.run()
|
128
|
+
reason = ", because the App it is defined on is not running"
|
129
|
+
else:
|
130
|
+
# Technically possible, but with an ambiguous cause.
|
131
|
+
reason = ""
|
132
|
+
raise ExecutionError(
|
133
|
+
f"{object_type} has not been hydrated with the metadata it needs to run on Modal{reason}."
|
134
|
+
)
|
135
|
+
|
136
|
+
def clone(self) -> Self:
|
137
|
+
"""mdmd:hidden Clone a given hydrated object."""
|
138
|
+
|
139
|
+
# Object to clone must already be hydrated, otherwise from_loader is more suitable.
|
140
|
+
self._validate_is_hydrated()
|
141
|
+
obj = type(self).__new__(type(self))
|
142
|
+
obj._initialize_from_other(self)
|
143
|
+
return obj
|
144
|
+
|
145
|
+
@classmethod
|
146
|
+
def _from_loader(
|
147
|
+
cls,
|
148
|
+
load: Callable[[Self, Resolver, Optional[str]], Awaitable[None]],
|
149
|
+
rep: str,
|
150
|
+
is_another_app: bool = False,
|
151
|
+
preload: Optional[Callable[[Self, Resolver, Optional[str]], Awaitable[None]]] = None,
|
152
|
+
hydrate_lazily: bool = False,
|
153
|
+
deps: Optional[Callable[..., Sequence["_Object"]]] = None,
|
154
|
+
deduplication_key: Optional[Callable[[], Awaitable[Hashable]]] = None,
|
155
|
+
):
|
156
|
+
# TODO(erikbern): flip the order of the two first arguments
|
157
|
+
obj = _Object.__new__(cls)
|
158
|
+
obj._init(rep, load, is_another_app, preload, hydrate_lazily, deps, deduplication_key)
|
159
|
+
return obj
|
160
|
+
|
161
|
+
@staticmethod
|
162
|
+
def _get_type_from_id(object_id: str) -> type["_Object"]:
|
163
|
+
parts = object_id.split("-")
|
164
|
+
if len(parts) != 2:
|
165
|
+
raise InvalidError(f"Object id {object_id} has no dash in it")
|
166
|
+
prefix = parts[0]
|
167
|
+
if prefix not in _Object._prefix_to_type:
|
168
|
+
raise InvalidError(f"Object prefix {prefix} does not correspond to a type")
|
169
|
+
return _Object._prefix_to_type[prefix]
|
170
|
+
|
171
|
+
@classmethod
|
172
|
+
def _is_id_type(cls, object_id) -> bool:
|
173
|
+
return cls._get_type_from_id(object_id) == cls
|
174
|
+
|
175
|
+
@classmethod
|
176
|
+
def _new_hydrated(
|
177
|
+
cls, object_id: str, client: _Client, handle_metadata: Optional[Message], is_another_app: bool = False
|
178
|
+
) -> Self:
|
179
|
+
obj_cls: type[Self]
|
180
|
+
if cls._type_prefix is not None:
|
181
|
+
# This is called directly on a subclass, e.g. Secret.from_id
|
182
|
+
# validate the id matching the expected id type of the Object subclass
|
183
|
+
if not object_id.startswith(cls._type_prefix + "-"):
|
184
|
+
raise InvalidError(f"Object {object_id} does not start with {cls._type_prefix}")
|
185
|
+
|
186
|
+
obj_cls = cls
|
187
|
+
else:
|
188
|
+
# this means the method is used directly on _Object
|
189
|
+
# typically during deserialization of objects
|
190
|
+
obj_cls = typing.cast(type[Self], cls._get_type_from_id(object_id))
|
191
|
+
|
192
|
+
# Instantiate provider
|
193
|
+
obj = _Object.__new__(obj_cls)
|
194
|
+
rep = f"Object({object_id})" # TODO(erikbern): dumb
|
195
|
+
obj._init(rep, is_another_app=is_another_app)
|
196
|
+
obj._hydrate(object_id, client, handle_metadata)
|
197
|
+
|
198
|
+
return obj
|
199
|
+
|
200
|
+
def _hydrate_from_other(self, other: Self):
|
201
|
+
self._hydrate(other.object_id, other.client, other._get_metadata())
|
202
|
+
|
203
|
+
def __repr__(self):
|
204
|
+
return self._rep
|
205
|
+
|
206
|
+
@property
|
207
|
+
def local_uuid(self):
|
208
|
+
"""mdmd:hidden"""
|
209
|
+
return self._local_uuid
|
210
|
+
|
211
|
+
@property
|
212
|
+
def object_id(self) -> str:
|
213
|
+
"""mdmd:hidden"""
|
214
|
+
if self._object_id is None:
|
215
|
+
raise AttributeError(f"Attempting to get object_id of unhydrated {self}")
|
216
|
+
return self._object_id
|
217
|
+
|
218
|
+
@property
|
219
|
+
def client(self) -> _Client:
|
220
|
+
"""mdmd:hidden"""
|
221
|
+
if self._client is None:
|
222
|
+
raise AttributeError(f"Attempting to get client of unhydrated {self}")
|
223
|
+
return self._client
|
224
|
+
|
225
|
+
@property
|
226
|
+
def is_hydrated(self) -> bool:
|
227
|
+
"""mdmd:hidden"""
|
228
|
+
return self._is_hydrated
|
229
|
+
|
230
|
+
@property
|
231
|
+
def deps(self) -> Callable[..., Sequence["_Object"]]:
|
232
|
+
"""mdmd:hidden"""
|
233
|
+
|
234
|
+
def default_deps(*args, **kwargs) -> Sequence["_Object"]:
|
235
|
+
return []
|
236
|
+
|
237
|
+
return self._deps if self._deps is not None else default_deps
|
238
|
+
|
239
|
+
async def resolve(self, client: Optional[_Client] = None):
|
240
|
+
"""mdmd:hidden"""
|
241
|
+
if self._is_hydrated:
|
242
|
+
# memory snapshots capture references which must be rehydrated
|
243
|
+
# on restore to handle staleness.
|
244
|
+
if self.client._snapshotted and not self._is_rehydrated:
|
245
|
+
logger.debug(f"rehydrating {self} after snapshot")
|
246
|
+
self._is_hydrated = False # un-hydrate and re-resolve
|
247
|
+
c = client if client is not None else await _Client.from_env()
|
248
|
+
resolver = Resolver(c)
|
249
|
+
await resolver.load(typing.cast(_Object, self))
|
250
|
+
self._is_rehydrated = True
|
251
|
+
logger.debug(f"rehydrated {self} with client {id(c)}")
|
252
|
+
return
|
253
|
+
elif not self._hydrate_lazily:
|
254
|
+
self._validate_is_hydrated()
|
255
|
+
else:
|
256
|
+
# TODO: this client and/or resolver can't be changed by a caller to X.from_name()
|
257
|
+
c = client if client is not None else await _Client.from_env()
|
258
|
+
resolver = Resolver(c)
|
259
|
+
await resolver.load(self)
|
260
|
+
|
261
|
+
|
262
|
+
def live_method(method):
|
263
|
+
@wraps(method)
|
264
|
+
async def wrapped(self, *args, **kwargs):
|
265
|
+
await self.resolve()
|
266
|
+
return await method(self, *args, **kwargs)
|
267
|
+
|
268
|
+
return wrapped
|
269
|
+
|
270
|
+
|
271
|
+
def live_method_gen(method):
|
272
|
+
@wraps(method)
|
273
|
+
async def wrapped(self, *args, **kwargs):
|
274
|
+
await self.resolve()
|
275
|
+
async with aclosing(method(self, *args, **kwargs)) as stream:
|
276
|
+
async for item in stream:
|
277
|
+
yield item
|
278
|
+
|
279
|
+
return wrapped
|
modal/_resolver.py
CHANGED
@@ -15,7 +15,7 @@ from .exception import NotFoundError
|
|
15
15
|
if TYPE_CHECKING:
|
16
16
|
from rich.tree import Tree
|
17
17
|
|
18
|
-
|
18
|
+
import modal._object
|
19
19
|
|
20
20
|
|
21
21
|
class StatusRow:
|
@@ -33,7 +33,7 @@ class StatusRow:
|
|
33
33
|
self._spinner.update(text=message)
|
34
34
|
|
35
35
|
def finish(self, message):
|
36
|
-
if self._step_node is not None:
|
36
|
+
if self._step_node is not None and self._spinner is not None:
|
37
37
|
from ._output import OutputManager
|
38
38
|
|
39
39
|
self._spinner.update(text=message)
|
@@ -89,7 +89,7 @@ class Resolver:
|
|
89
89
|
if obj._preload is not None:
|
90
90
|
await obj._preload(obj, self, existing_object_id)
|
91
91
|
|
92
|
-
async def load(self, obj: "_Object", existing_object_id: Optional[str] = None):
|
92
|
+
async def load(self, obj: "modal._object._Object", existing_object_id: Optional[str] = None):
|
93
93
|
if obj._is_hydrated and obj._is_another_app:
|
94
94
|
# No need to reload this, it won't typically change
|
95
95
|
if obj.local_uuid not in self._local_uuid_to_future:
|
@@ -124,6 +124,8 @@ class Resolver:
|
|
124
124
|
await TaskContext.gather(*[self.load(dep) for dep in obj.deps()])
|
125
125
|
|
126
126
|
# Load the object itself
|
127
|
+
if not obj._load:
|
128
|
+
raise Exception(f"Object {obj} has no loader function")
|
127
129
|
try:
|
128
130
|
await obj._load(obj, self, existing_object_id)
|
129
131
|
except GRPCError as exc:
|
@@ -154,8 +156,8 @@ class Resolver:
|
|
154
156
|
# TODO(elias): print original exception/trace rather than the Resolver-internal trace
|
155
157
|
return await cached_future
|
156
158
|
|
157
|
-
def objects(self) -> list["_Object"]:
|
158
|
-
unique_objects: dict[str, "_Object"] = {}
|
159
|
+
def objects(self) -> list["modal._object._Object"]:
|
160
|
+
unique_objects: dict[str, "modal._object._Object"] = {}
|
159
161
|
for fut in self._local_uuid_to_future.values():
|
160
162
|
if not fut.done():
|
161
163
|
# this will raise an exception if not all loads have been awaited, but that *should* never happen
|
@@ -3,11 +3,11 @@ import importlib
|
|
3
3
|
import typing
|
4
4
|
from abc import ABCMeta, abstractmethod
|
5
5
|
from dataclasses import dataclass
|
6
|
-
from typing import Any, Callable, Optional
|
6
|
+
from typing import Any, Callable, Optional, Sequence
|
7
7
|
|
8
|
+
import modal._object
|
8
9
|
import modal._runtime.container_io_manager
|
9
10
|
import modal.cls
|
10
|
-
import modal.object
|
11
11
|
from modal import Function
|
12
12
|
from modal._utils.async_utils import synchronizer
|
13
13
|
from modal._utils.function_utils import LocalFunctionError, is_async as get_is_async, is_global_object
|
@@ -41,7 +41,7 @@ class Service(metaclass=ABCMeta):
|
|
41
41
|
|
42
42
|
user_cls_instance: Any
|
43
43
|
app: Optional["modal.app._App"]
|
44
|
-
code_deps: Optional[
|
44
|
+
code_deps: Optional[Sequence["modal._object._Object"]]
|
45
45
|
|
46
46
|
@abstractmethod
|
47
47
|
def get_finalized_functions(
|
@@ -94,7 +94,7 @@ def construct_webhook_callable(
|
|
94
94
|
class ImportedFunction(Service):
|
95
95
|
user_cls_instance: Any
|
96
96
|
app: Optional["modal.app._App"]
|
97
|
-
code_deps: Optional[
|
97
|
+
code_deps: Optional[Sequence["modal._object._Object"]]
|
98
98
|
|
99
99
|
_user_defined_callable: Callable[..., Any]
|
100
100
|
|
@@ -137,7 +137,7 @@ class ImportedFunction(Service):
|
|
137
137
|
class ImportedClass(Service):
|
138
138
|
user_cls_instance: Any
|
139
139
|
app: Optional["modal.app._App"]
|
140
|
-
code_deps: Optional[
|
140
|
+
code_deps: Optional[Sequence["modal._object._Object"]]
|
141
141
|
|
142
142
|
_partial_functions: dict[str, "modal.partial_function._PartialFunction"]
|
143
143
|
|
@@ -229,7 +229,7 @@ def import_single_function_service(
|
|
229
229
|
"""
|
230
230
|
user_defined_callable: Callable
|
231
231
|
function: Optional[_Function] = None
|
232
|
-
code_deps: Optional[
|
232
|
+
code_deps: Optional[Sequence["modal._object._Object"]] = None
|
233
233
|
active_app: Optional[modal.app._App] = None
|
234
234
|
|
235
235
|
if ser_fun is not None:
|
@@ -306,7 +306,7 @@ def import_class_service(
|
|
306
306
|
See import_function.
|
307
307
|
"""
|
308
308
|
active_app: Optional["modal.app._App"]
|
309
|
-
code_deps: Optional[
|
309
|
+
code_deps: Optional[Sequence["modal._object._Object"]]
|
310
310
|
cls: typing.Union[type, modal.cls.Cls]
|
311
311
|
|
312
312
|
if function_def.definition_type == api_pb2.Function.DEFINITION_TYPE_SERIALIZED:
|
modal/_serialization.py
CHANGED
@@ -8,10 +8,11 @@ from typing import Any
|
|
8
8
|
from modal._utils.async_utils import synchronizer
|
9
9
|
from modal_proto import api_pb2
|
10
10
|
|
11
|
+
from ._object import _Object
|
11
12
|
from ._vendor import cloudpickle
|
12
13
|
from .config import logger
|
13
14
|
from .exception import DeserializationError, ExecutionError, InvalidError
|
14
|
-
from .object import Object
|
15
|
+
from .object import Object
|
15
16
|
|
16
17
|
PICKLE_PROTOCOL = 4 # Support older Python versions.
|
17
18
|
|
@@ -48,8 +49,8 @@ class Pickler(cloudpickle.Pickler):
|
|
48
49
|
return ("sync", (impl_object.__class__, attributes))
|
49
50
|
else:
|
50
51
|
return
|
51
|
-
if not obj.
|
52
|
-
raise InvalidError(f"Can't serialize object {obj} which hasn't been
|
52
|
+
if not obj.is_hydrated:
|
53
|
+
raise InvalidError(f"Can't serialize object {obj} which hasn't been hydrated.")
|
53
54
|
return (obj.object_id, flag, obj._get_metadata())
|
54
55
|
|
55
56
|
|
modal/app.py
CHANGED
@@ -21,6 +21,7 @@ from synchronicity.async_wrap import asynccontextmanager
|
|
21
21
|
from modal_proto import api_pb2
|
22
22
|
|
23
23
|
from ._ipython import is_notebook
|
24
|
+
from ._object import _get_environment_name, _Object
|
24
25
|
from ._utils.async_utils import synchronize_api
|
25
26
|
from ._utils.deprecation import deprecation_error, deprecation_warning, renamed_parameter
|
26
27
|
from ._utils.function_utils import FunctionInfo, is_global_object, is_method_fn
|
@@ -36,7 +37,6 @@ from .gpu import GPU_T
|
|
36
37
|
from .image import _Image
|
37
38
|
from .mount import _Mount
|
38
39
|
from .network_file_system import _NetworkFileSystem
|
39
|
-
from .object import _get_environment_name, _Object
|
40
40
|
from .partial_function import (
|
41
41
|
PartialFunction,
|
42
42
|
_find_partial_methods_for_user_cls,
|
modal/app.pyi
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
import collections.abc
|
2
|
+
import modal._object
|
2
3
|
import modal._utils.function_utils
|
3
4
|
import modal.client
|
4
5
|
import modal.cloud_bucket_mount
|
@@ -115,9 +116,9 @@ class _App:
|
|
115
116
|
def set_description(self, description: str): ...
|
116
117
|
def _validate_blueprint_value(self, key: str, value: typing.Any): ...
|
117
118
|
def __getitem__(self, tag: str): ...
|
118
|
-
def __setitem__(self, tag: str, obj: modal.
|
119
|
+
def __setitem__(self, tag: str, obj: modal._object._Object): ...
|
119
120
|
def __getattr__(self, tag: str): ...
|
120
|
-
def __setattr__(self, tag: str, obj: modal.
|
121
|
+
def __setattr__(self, tag: str, obj: modal._object._Object): ...
|
121
122
|
@property
|
122
123
|
def image(self) -> modal.image._Image: ...
|
123
124
|
@image.setter
|
@@ -146,7 +147,7 @@ class _App:
|
|
146
147
|
@property
|
147
148
|
def registered_entrypoints(self) -> dict[str, _LocalEntrypoint]: ...
|
148
149
|
@property
|
149
|
-
def indexed_objects(self) -> dict[str, modal.
|
150
|
+
def indexed_objects(self) -> dict[str, modal._object._Object]: ...
|
150
151
|
@property
|
151
152
|
def registered_web_endpoints(self) -> list[str]: ...
|
152
153
|
def local_entrypoint(
|
modal/cli/app.py
CHANGED
@@ -9,11 +9,11 @@ from rich.table import Column
|
|
9
9
|
from rich.text import Text
|
10
10
|
from typer import Argument
|
11
11
|
|
12
|
+
from modal._object import _get_environment_name
|
12
13
|
from modal._utils.async_utils import synchronizer
|
13
14
|
from modal._utils.deprecation import deprecation_warning
|
14
15
|
from modal.client import _Client
|
15
16
|
from modal.environments import ensure_env
|
16
|
-
from modal.object import _get_environment_name
|
17
17
|
from modal_proto import api_pb2
|
18
18
|
|
19
19
|
from .utils import ENV_OPTION, display_table, get_app_id_from_name, stream_app_logs, timestamp_to_local
|
modal/cli/container.py
CHANGED
@@ -4,6 +4,7 @@ from typing import Optional, Union
|
|
4
4
|
import typer
|
5
5
|
from rich.text import Text
|
6
6
|
|
7
|
+
from modal._object import _get_environment_name
|
7
8
|
from modal._pty import get_pty_info
|
8
9
|
from modal._utils.async_utils import synchronizer
|
9
10
|
from modal._utils.grpc_utils import retry_transient_errors
|
@@ -12,7 +13,6 @@ from modal.client import _Client
|
|
12
13
|
from modal.config import config
|
13
14
|
from modal.container_process import _ContainerProcess
|
14
15
|
from modal.environments import ensure_env
|
15
|
-
from modal.object import _get_environment_name
|
16
16
|
from modal.stream_type import StreamType
|
17
17
|
from modal_proto import api_pb2
|
18
18
|
|
modal/client.py
CHANGED
modal/client.pyi
CHANGED
@@ -24,9 +24,10 @@ class _Client:
|
|
24
24
|
_cancellation_context: modal._utils.async_utils.TaskContext
|
25
25
|
_cancellation_context_event_loop: asyncio.events.AbstractEventLoop
|
26
26
|
_stub: typing.Optional[modal_proto.api_grpc.ModalClientStub]
|
27
|
+
_snapshotted: bool
|
27
28
|
|
28
29
|
def __init__(
|
29
|
-
self, server_url: str, client_type: int, credentials: typing.Optional[tuple[str, str]], version: str = "0.72.
|
30
|
+
self, server_url: str, client_type: int, credentials: typing.Optional[tuple[str, str]], version: str = "0.72.22"
|
30
31
|
): ...
|
31
32
|
def is_closed(self) -> bool: ...
|
32
33
|
@property
|
@@ -79,9 +80,10 @@ class Client:
|
|
79
80
|
_cancellation_context: modal._utils.async_utils.TaskContext
|
80
81
|
_cancellation_context_event_loop: asyncio.events.AbstractEventLoop
|
81
82
|
_stub: typing.Optional[modal_proto.api_grpc.ModalClientStub]
|
83
|
+
_snapshotted: bool
|
82
84
|
|
83
85
|
def __init__(
|
84
|
-
self, server_url: str, client_type: int, credentials: typing.Optional[tuple[str, str]], version: str = "0.72.
|
86
|
+
self, server_url: str, client_type: int, credentials: typing.Optional[tuple[str, str]], version: str = "0.72.22"
|
85
87
|
): ...
|
86
88
|
def is_closed(self) -> bool: ...
|
87
89
|
@property
|
modal/cls.py
CHANGED
@@ -11,6 +11,7 @@ from grpclib import GRPCError, Status
|
|
11
11
|
from modal._utils.function_utils import CLASS_PARAM_TYPE_MAP
|
12
12
|
from modal_proto import api_pb2
|
13
13
|
|
14
|
+
from ._object import _get_environment_name, _Object
|
14
15
|
from ._resolver import Resolver
|
15
16
|
from ._resources import convert_fn_config_to_resources_config
|
16
17
|
from ._serialization import check_valid_cls_constructor_arg
|
@@ -23,7 +24,6 @@ from .client import _Client
|
|
23
24
|
from .exception import ExecutionError, InvalidError, NotFoundError, VersionError
|
24
25
|
from .functions import _Function, _parse_retries
|
25
26
|
from .gpu import GPU_T
|
26
|
-
from .object import _get_environment_name, _Object
|
27
27
|
from .partial_function import (
|
28
28
|
_find_callables_for_obj,
|
29
29
|
_find_partial_methods_for_user_cls,
|
modal/cls.pyi
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
import collections.abc
|
2
2
|
import google.protobuf.message
|
3
3
|
import inspect
|
4
|
+
import modal._object
|
4
5
|
import modal.app
|
5
6
|
import modal.client
|
6
7
|
import modal.functions
|
@@ -91,7 +92,7 @@ class Obj:
|
|
91
92
|
async def _aenter(self): ...
|
92
93
|
def __getattr__(self, k): ...
|
93
94
|
|
94
|
-
class _Cls(modal.
|
95
|
+
class _Cls(modal._object._Object):
|
95
96
|
_user_cls: typing.Optional[type]
|
96
97
|
_class_service_function: typing.Optional[modal.functions._Function]
|
97
98
|
_method_functions: typing.Optional[dict[str, modal.functions._Function]]
|
modal/dict.py
CHANGED
@@ -7,6 +7,7 @@ from synchronicity.async_wrap import asynccontextmanager
|
|
7
7
|
|
8
8
|
from modal_proto import api_pb2
|
9
9
|
|
10
|
+
from ._object import EPHEMERAL_OBJECT_HEARTBEAT_SLEEP, _get_environment_name, _Object, live_method, live_method_gen
|
10
11
|
from ._resolver import Resolver
|
11
12
|
from ._serialization import deserialize, serialize
|
12
13
|
from ._utils.async_utils import TaskContext, synchronize_api
|
@@ -16,7 +17,6 @@ from ._utils.name_utils import check_object_name
|
|
16
17
|
from .client import _Client
|
17
18
|
from .config import logger
|
18
19
|
from .exception import RequestSizeError
|
19
|
-
from .object import EPHEMERAL_OBJECT_HEARTBEAT_SLEEP, _get_environment_name, _Object, live_method, live_method_gen
|
20
20
|
|
21
21
|
|
22
22
|
def _serialize_dict(data):
|
modal/dict.pyi
CHANGED
@@ -1,4 +1,5 @@
|
|
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
|
@@ -7,7 +8,7 @@ import typing_extensions
|
|
7
8
|
|
8
9
|
def _serialize_dict(data): ...
|
9
10
|
|
10
|
-
class _Dict(modal.
|
11
|
+
class _Dict(modal._object._Object):
|
11
12
|
def __init__(self, data={}): ...
|
12
13
|
@classmethod
|
13
14
|
def ephemeral(
|
modal/environments.py
CHANGED
@@ -8,6 +8,7 @@ from google.protobuf.wrappers_pb2 import StringValue
|
|
8
8
|
|
9
9
|
from modal_proto import api_pb2
|
10
10
|
|
11
|
+
from ._object import _Object
|
11
12
|
from ._resolver import Resolver
|
12
13
|
from ._utils.async_utils import synchronize_api, synchronizer
|
13
14
|
from ._utils.deprecation import renamed_parameter
|
@@ -15,7 +16,6 @@ from ._utils.grpc_utils import retry_transient_errors
|
|
15
16
|
from ._utils.name_utils import check_object_name
|
16
17
|
from .client import _Client
|
17
18
|
from .config import config, logger
|
18
|
-
from .object import _Object
|
19
19
|
|
20
20
|
|
21
21
|
@dataclass(frozen=True)
|
modal/environments.pyi
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
import google.protobuf.message
|
2
|
+
import modal._object
|
2
3
|
import modal.client
|
3
4
|
import modal.object
|
4
5
|
import modal_proto.api_pb2
|
@@ -16,7 +17,7 @@ class EnvironmentSettings:
|
|
16
17
|
def __delattr__(self, name): ...
|
17
18
|
def __hash__(self): ...
|
18
19
|
|
19
|
-
class _Environment(modal.
|
20
|
+
class _Environment(modal._object._Object):
|
20
21
|
_settings: EnvironmentSettings
|
21
22
|
|
22
23
|
def __init__(self): ...
|