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/object.py CHANGED
@@ -1,268 +1,5 @@
1
- # Copyright Modal Labs 2022
2
- import uuid
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[[_BLOCKING_O, modal._resolver.Resolver, typing.Optional[str]], collections.abc.Awaitable[None]]
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[[_BLOCKING_O, modal._resolver.Resolver, typing.Optional[str]], collections.abc.Awaitable[None]]
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[..., list[Object]]]
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[[_BLOCKING_O, modal._resolver.Resolver, typing.Optional[str]], None]
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[[_BLOCKING_O, modal._resolver.Resolver, typing.Optional[str]], None]
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[..., list[Object]]] = None,
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
- [_BLOCKING_O, modal._resolver.Resolver, typing.Optional[str]], collections.abc.Awaitable[None]
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
- [_BLOCKING_O, modal._resolver.Resolver, typing.Optional[str]], collections.abc.Awaitable[None]
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[..., list[Object]]] = None,
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: _BLOCKING_O): ...
173
- def clone(self: _BLOCKING_O) -> _BLOCKING_O: ...
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[[_BLOCKING_O, modal._resolver.Resolver, typing.Optional[str]], None],
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[[_BLOCKING_O, modal._resolver.Resolver, typing.Optional[str]], None]
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 _get_type_from_id(cls: type[_BLOCKING_O], object_id: str) -> type[_BLOCKING_O]: ...
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: type[_BLOCKING_O],
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
- ) -> _BLOCKING_O: ...
199
- def _hydrate_from_other(self, other: _BLOCKING_O): ...
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[..., list[Object]]: ...
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
@@ -1,7 +1,8 @@
1
+ import modal._object
1
2
  import modal.object
2
3
  import typing
3
4
 
4
- class _Proxy(modal.object._Object):
5
+ class _Proxy(modal._object._Object):
5
6
  @staticmethod
6
7
  def from_name(name: str, environment_name: typing.Optional[str] = None) -> _Proxy: ...
7
8
 
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.object._Object):
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.object_id is not None:
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.object._Object):
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.object._Object):
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.object._Object):
37
+ class _Volume(modal._object._Object):
37
38
  _lock: typing.Optional[asyncio.locks.Lock]
38
39
 
39
40
  async def _get_lock(self): ...