modal 0.72.38__py3-none-any.whl → 0.72.40__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
@@ -8,9 +8,9 @@ from typing import Callable, ClassVar, Optional
8
8
  from google.protobuf.message import Message
9
9
  from typing_extensions import Self
10
10
 
11
- from modal._utils.async_utils import aclosing
12
-
13
11
  from ._resolver import Resolver
12
+ from ._utils.async_utils import aclosing
13
+ from ._utils.deprecation import deprecation_warning
14
14
  from .client import _Client
15
15
  from .config import config, logger
16
16
  from .exception import ExecutionError, InvalidError
@@ -238,10 +238,29 @@ class _Object:
238
238
 
239
239
  async def resolve(self, client: Optional[_Client] = None):
240
240
  """mdmd:hidden"""
241
+ obj = self.__class__.__name__.strip("_")
242
+ deprecation_warning(
243
+ (2025, 1, 16),
244
+ f"The `{obj}.resolve` method is deprecated and will be removed in a future release."
245
+ f" Please use `{obj}.hydrate()` or `await {obj}.hydrate.aio()` instead."
246
+ "\n\nNote that it is rarely necessary to explicitly hydrate objects, as most methods"
247
+ " will lazily hydrate when needed.",
248
+ show_source=False, # synchronicity interferes with attributing source correctly
249
+ pending=True,
250
+ )
251
+ await self.hydrate(client)
252
+
253
+ async def hydrate(self, client: Optional[_Client] = None) -> Self:
254
+ """Synchronize the local object with its identity on the Modal server.
255
+
256
+ It is rarely necessary to call this method explicitly, as most operations
257
+ will lazily hydrate when needed. The main use case is when you need to
258
+ access object metadata, such as its ID.
259
+ """
241
260
  if self._is_hydrated:
242
- # memory snapshots capture references which must be rehydrated
243
- # on restore to handle staleness.
244
261
  if self.client._snapshotted and not self._is_rehydrated:
262
+ # memory snapshots capture references which must be rehydrated
263
+ # on restore to handle staleness.
245
264
  logger.debug(f"rehydrating {self} after snapshot")
246
265
  self._is_hydrated = False # un-hydrate and re-resolve
247
266
  c = client if client is not None else await _Client.from_env()
@@ -249,20 +268,20 @@ class _Object:
249
268
  await resolver.load(typing.cast(_Object, self))
250
269
  self._is_rehydrated = True
251
270
  logger.debug(f"rehydrated {self} with client {id(c)}")
252
- return
253
271
  elif not self._hydrate_lazily:
272
+ # TODO(michael) can remove _hydrate lazily? I think all objects support it now?
254
273
  self._validate_is_hydrated()
255
274
  else:
256
- # TODO: this client and/or resolver can't be changed by a caller to X.from_name()
257
275
  c = client if client is not None else await _Client.from_env()
258
276
  resolver = Resolver(c)
259
277
  await resolver.load(self)
278
+ return self
260
279
 
261
280
 
262
281
  def live_method(method):
263
282
  @wraps(method)
264
283
  async def wrapped(self, *args, **kwargs):
265
- await self.resolve()
284
+ await self.hydrate()
266
285
  return await method(self, *args, **kwargs)
267
286
 
268
287
  return wrapped
@@ -271,7 +290,7 @@ def live_method(method):
271
290
  def live_method_gen(method):
272
291
  @wraps(method)
273
292
  async def wrapped(self, *args, **kwargs):
274
- await self.resolve()
293
+ await self.hydrate()
275
294
  async with aclosing(method(self, *args, **kwargs)) as stream:
276
295
  async for item in stream:
277
296
  yield item
modal/app.pyi CHANGED
@@ -67,10 +67,12 @@ class _FunctionDecoratorType:
67
67
  ) -> modal.functions.Function[P, ReturnType, OriginalReturnType]: ...
68
68
  @typing.overload
69
69
  def __call__(
70
- self, func: typing.Callable[P, collections.abc.Coroutine[typing.Any, typing.Any, ReturnType]]
70
+ self, func: collections.abc.Callable[P, collections.abc.Coroutine[typing.Any, typing.Any, ReturnType]]
71
71
  ) -> modal.functions.Function[P, ReturnType, collections.abc.Coroutine[typing.Any, typing.Any, ReturnType]]: ...
72
72
  @typing.overload
73
- def __call__(self, func: typing.Callable[P, ReturnType]) -> modal.functions.Function[P, ReturnType, ReturnType]: ...
73
+ def __call__(
74
+ self, func: collections.abc.Callable[P, ReturnType]
75
+ ) -> modal.functions.Function[P, ReturnType, ReturnType]: ...
74
76
 
75
77
  class _App:
76
78
  _all_apps: typing.ClassVar[dict[typing.Optional[str], list[_App]]]
@@ -152,7 +154,7 @@ class _App:
152
154
  def registered_web_endpoints(self) -> list[str]: ...
153
155
  def local_entrypoint(
154
156
  self, _warn_parentheses_missing: typing.Any = None, *, name: typing.Optional[str] = None
155
- ) -> typing.Callable[[typing.Callable[..., typing.Any]], _LocalEntrypoint]: ...
157
+ ) -> collections.abc.Callable[[collections.abc.Callable[..., typing.Any]], _LocalEntrypoint]: ...
156
158
  def function(
157
159
  self,
158
160
  _warn_parentheses_missing: typing.Any = None,
@@ -238,7 +240,7 @@ class _App:
238
240
  _experimental_buffer_containers: typing.Optional[int] = None,
239
241
  _experimental_proxy_ip: typing.Optional[str] = None,
240
242
  _experimental_custom_scaling_factor: typing.Optional[float] = None,
241
- ) -> typing.Callable[[CLS_T], CLS_T]: ...
243
+ ) -> collections.abc.Callable[[CLS_T], CLS_T]: ...
242
244
  async def spawn_sandbox(
243
245
  self,
244
246
  *entrypoint_args: str,
@@ -272,6 +274,8 @@ class _App:
272
274
  @classmethod
273
275
  def _reset_container_app(cls): ...
274
276
 
277
+ SUPERSELF = typing.TypeVar("SUPERSELF", covariant=True)
278
+
275
279
  class App:
276
280
  _all_apps: typing.ClassVar[dict[typing.Optional[str], list[App]]]
277
281
  _container_app: typing.ClassVar[typing.Optional[App]]
@@ -337,7 +341,7 @@ class App:
337
341
  def image(self, value): ...
338
342
  def _uncreate_all_objects(self): ...
339
343
 
340
- class ___set_local_app_spec(typing_extensions.Protocol):
344
+ class ___set_local_app_spec(typing_extensions.Protocol[SUPERSELF]):
341
345
  def __call__(
342
346
  self, client: modal.client.Client, running_app: modal.running_app.RunningApp
343
347
  ) -> synchronicity.combined_types.AsyncAndBlockingContextManager[None]: ...
@@ -345,9 +349,9 @@ class App:
345
349
  self, client: modal.client.Client, running_app: modal.running_app.RunningApp
346
350
  ) -> typing.AsyncContextManager[None]: ...
347
351
 
348
- _set_local_app: ___set_local_app_spec
352
+ _set_local_app: ___set_local_app_spec[typing_extensions.Self]
349
353
 
350
- class __run_spec(typing_extensions.Protocol):
354
+ class __run_spec(typing_extensions.Protocol[SUPERSELF]):
351
355
  def __call__(
352
356
  self,
353
357
  client: typing.Optional[modal.client.Client] = None,
@@ -365,7 +369,7 @@ class App:
365
369
  environment_name: typing.Optional[str] = None,
366
370
  ) -> typing.AsyncContextManager[App]: ...
367
371
 
368
- run: __run_spec
372
+ run: __run_spec[typing_extensions.Self]
369
373
 
370
374
  def _get_default_image(self): ...
371
375
  def _get_watch_mounts(self): ...
@@ -384,7 +388,7 @@ class App:
384
388
  def registered_web_endpoints(self) -> list[str]: ...
385
389
  def local_entrypoint(
386
390
  self, _warn_parentheses_missing: typing.Any = None, *, name: typing.Optional[str] = None
387
- ) -> typing.Callable[[typing.Callable[..., typing.Any]], LocalEntrypoint]: ...
391
+ ) -> collections.abc.Callable[[collections.abc.Callable[..., typing.Any]], LocalEntrypoint]: ...
388
392
  def function(
389
393
  self,
390
394
  _warn_parentheses_missing: typing.Any = None,
@@ -470,9 +474,9 @@ class App:
470
474
  _experimental_buffer_containers: typing.Optional[int] = None,
471
475
  _experimental_proxy_ip: typing.Optional[str] = None,
472
476
  _experimental_custom_scaling_factor: typing.Optional[float] = None,
473
- ) -> typing.Callable[[CLS_T], CLS_T]: ...
477
+ ) -> collections.abc.Callable[[CLS_T], CLS_T]: ...
474
478
 
475
- class __spawn_sandbox_spec(typing_extensions.Protocol):
479
+ class __spawn_sandbox_spec(typing_extensions.Protocol[SUPERSELF]):
476
480
  def __call__(
477
481
  self,
478
482
  *entrypoint_args: str,
@@ -522,11 +526,11 @@ class App:
522
526
  _experimental_scheduler_placement: typing.Optional[modal.scheduler_placement.SchedulerPlacement] = None,
523
527
  ) -> None: ...
524
528
 
525
- spawn_sandbox: __spawn_sandbox_spec
529
+ spawn_sandbox: __spawn_sandbox_spec[typing_extensions.Self]
526
530
 
527
531
  def include(self, /, other_app: App): ...
528
532
 
529
- class ___logs_spec(typing_extensions.Protocol):
533
+ class ___logs_spec(typing_extensions.Protocol[SUPERSELF]):
530
534
  def __call__(
531
535
  self, client: typing.Optional[modal.client.Client] = None
532
536
  ) -> typing.Generator[str, None, None]: ...
@@ -534,7 +538,7 @@ class App:
534
538
  self, client: typing.Optional[modal.client.Client] = None
535
539
  ) -> collections.abc.AsyncGenerator[str, None]: ...
536
540
 
537
- _logs: ___logs_spec
541
+ _logs: ___logs_spec[typing_extensions.Self]
538
542
 
539
543
  @classmethod
540
544
  def _get_container_app(cls) -> typing.Optional[App]: ...
modal/client.pyi CHANGED
@@ -27,7 +27,7 @@ class _Client:
27
27
  _snapshotted: bool
28
28
 
29
29
  def __init__(
30
- self, server_url: str, client_type: int, credentials: typing.Optional[tuple[str, str]], version: str = "0.72.38"
30
+ self, server_url: str, client_type: int, credentials: typing.Optional[tuple[str, str]], version: str = "0.72.40"
31
31
  ): ...
32
32
  def is_closed(self) -> bool: ...
33
33
  @property
@@ -74,6 +74,8 @@ class _Client:
74
74
  ],
75
75
  ) -> collections.abc.AsyncGenerator[typing.Any, None]: ...
76
76
 
77
+ SUPERSELF = typing.TypeVar("SUPERSELF", covariant=True)
78
+
77
79
  class Client:
78
80
  _client_from_env: typing.ClassVar[typing.Optional[Client]]
79
81
  _client_from_env_lock: typing.ClassVar[typing.Optional[asyncio.locks.Lock]]
@@ -83,29 +85,29 @@ class Client:
83
85
  _snapshotted: bool
84
86
 
85
87
  def __init__(
86
- self, server_url: str, client_type: int, credentials: typing.Optional[tuple[str, str]], version: str = "0.72.38"
88
+ self, server_url: str, client_type: int, credentials: typing.Optional[tuple[str, str]], version: str = "0.72.40"
87
89
  ): ...
88
90
  def is_closed(self) -> bool: ...
89
91
  @property
90
92
  def stub(self) -> modal_proto.modal_api_grpc.ModalClientModal: ...
91
93
 
92
- class ___open_spec(typing_extensions.Protocol):
94
+ class ___open_spec(typing_extensions.Protocol[SUPERSELF]):
93
95
  def __call__(self): ...
94
96
  async def aio(self): ...
95
97
 
96
- _open: ___open_spec
98
+ _open: ___open_spec[typing_extensions.Self]
97
99
 
98
- class ___close_spec(typing_extensions.Protocol):
100
+ class ___close_spec(typing_extensions.Protocol[SUPERSELF]):
99
101
  def __call__(self, prep_for_restore: bool = False): ...
100
102
  async def aio(self, prep_for_restore: bool = False): ...
101
103
 
102
- _close: ___close_spec
104
+ _close: ___close_spec[typing_extensions.Self]
103
105
 
104
- class __hello_spec(typing_extensions.Protocol):
106
+ class __hello_spec(typing_extensions.Protocol[SUPERSELF]):
105
107
  def __call__(self): ...
106
108
  async def aio(self): ...
107
109
 
108
- hello: __hello_spec
110
+ hello: __hello_spec[typing_extensions.Self]
109
111
 
110
112
  def __enter__(self): ...
111
113
  async def __aenter__(self): ...
@@ -122,23 +124,23 @@ class Client:
122
124
  @classmethod
123
125
  def set_env_client(cls, client: typing.Optional[Client]): ...
124
126
 
125
- class ___call_safely_spec(typing_extensions.Protocol):
127
+ class ___call_safely_spec(typing_extensions.Protocol[SUPERSELF]):
126
128
  def __call__(self, coro, readable_method: str): ...
127
129
  async def aio(self, coro, readable_method: str): ...
128
130
 
129
- _call_safely: ___call_safely_spec
131
+ _call_safely: ___call_safely_spec[typing_extensions.Self]
130
132
 
131
- class ___reset_on_pid_change_spec(typing_extensions.Protocol):
133
+ class ___reset_on_pid_change_spec(typing_extensions.Protocol[SUPERSELF]):
132
134
  def __call__(self): ...
133
135
  async def aio(self): ...
134
136
 
135
- _reset_on_pid_change: ___reset_on_pid_change_spec
137
+ _reset_on_pid_change: ___reset_on_pid_change_spec[typing_extensions.Self]
136
138
 
137
- class ___get_grpclib_method_spec(typing_extensions.Protocol):
139
+ class ___get_grpclib_method_spec(typing_extensions.Protocol[SUPERSELF]):
138
140
  def __call__(self, method_name: str) -> typing.Any: ...
139
141
  async def aio(self, method_name: str) -> typing.Any: ...
140
142
 
141
- _get_grpclib_method: ___get_grpclib_method_spec
143
+ _get_grpclib_method: ___get_grpclib_method_spec[typing_extensions.Self]
142
144
 
143
145
  async def _call_unary(
144
146
  self,
modal/cls.pyi CHANGED
@@ -55,6 +55,8 @@ class _Obj:
55
55
  async def _aenter(self): ...
56
56
  def __getattr__(self, k): ...
57
57
 
58
+ SUPERSELF = typing.TypeVar("SUPERSELF", covariant=True)
59
+
58
60
  class Obj:
59
61
  _cls: Cls
60
62
  _functions: dict[str, modal.functions.Function]
@@ -77,11 +79,11 @@ class Obj:
77
79
  def _get_parameter_values(self) -> dict[str, typing.Any]: ...
78
80
  def _new_user_cls_instance(self): ...
79
81
 
80
- class __keep_warm_spec(typing_extensions.Protocol):
82
+ class __keep_warm_spec(typing_extensions.Protocol[SUPERSELF]):
81
83
  def __call__(self, warm_pool_size: int) -> None: ...
82
84
  async def aio(self, warm_pool_size: int) -> None: ...
83
85
 
84
- keep_warm: __keep_warm_spec
86
+ keep_warm: __keep_warm_spec[typing_extensions.Self]
85
87
 
86
88
  def _cached_user_cls_instance(self): ...
87
89
  def _enter(self): ...
@@ -97,7 +99,7 @@ class _Cls(modal._object._Object):
97
99
  _class_service_function: typing.Optional[modal.functions._Function]
98
100
  _method_functions: typing.Optional[dict[str, modal.functions._Function]]
99
101
  _options: typing.Optional[modal_proto.api_pb2.FunctionOptions]
100
- _callables: dict[str, typing.Callable[..., typing.Any]]
102
+ _callables: dict[str, collections.abc.Callable[..., typing.Any]]
101
103
  _app: typing.Optional[modal.app._App]
102
104
  _name: typing.Optional[str]
103
105
 
@@ -154,7 +156,7 @@ class Cls(modal.object.Object):
154
156
  _class_service_function: typing.Optional[modal.functions.Function]
155
157
  _method_functions: typing.Optional[dict[str, modal.functions.Function]]
156
158
  _options: typing.Optional[modal_proto.api_pb2.FunctionOptions]
157
- _callables: dict[str, typing.Callable[..., typing.Any]]
159
+ _callables: dict[str, collections.abc.Callable[..., typing.Any]]
158
160
  _app: typing.Optional[modal.app.App]
159
161
  _name: typing.Optional[str]
160
162
 
@@ -36,6 +36,8 @@ class _ContainerProcess(typing.Generic[T]):
36
36
  async def wait(self) -> int: ...
37
37
  async def attach(self, *, pty: typing.Optional[bool] = None): ...
38
38
 
39
+ SUPERSELF = typing.TypeVar("SUPERSELF", covariant=True)
40
+
39
41
  class ContainerProcess(typing.Generic[T]):
40
42
  _process_id: typing.Optional[str]
41
43
  _stdout: modal.io_streams.StreamReader[T]
@@ -63,20 +65,20 @@ class ContainerProcess(typing.Generic[T]):
63
65
  @property
64
66
  def returncode(self) -> int: ...
65
67
 
66
- class __poll_spec(typing_extensions.Protocol):
68
+ class __poll_spec(typing_extensions.Protocol[SUPERSELF]):
67
69
  def __call__(self) -> typing.Optional[int]: ...
68
70
  async def aio(self) -> typing.Optional[int]: ...
69
71
 
70
- poll: __poll_spec
72
+ poll: __poll_spec[typing_extensions.Self]
71
73
 
72
- class __wait_spec(typing_extensions.Protocol):
74
+ class __wait_spec(typing_extensions.Protocol[SUPERSELF]):
73
75
  def __call__(self) -> int: ...
74
76
  async def aio(self) -> int: ...
75
77
 
76
- wait: __wait_spec
78
+ wait: __wait_spec[typing_extensions.Self]
77
79
 
78
- class __attach_spec(typing_extensions.Protocol):
80
+ class __attach_spec(typing_extensions.Protocol[SUPERSELF]):
79
81
  def __call__(self, *, pty: typing.Optional[bool] = None): ...
80
82
  async def aio(self, *, pty: typing.Optional[bool] = None): ...
81
83
 
82
- attach: __attach_spec
84
+ attach: __attach_spec[typing_extensions.Self]
modal/dict.pyi CHANGED
@@ -57,6 +57,8 @@ class _Dict(modal._object._Object):
57
57
  def values(self) -> collections.abc.AsyncIterator[typing.Any]: ...
58
58
  def items(self) -> collections.abc.AsyncIterator[tuple[typing.Any, typing.Any]]: ...
59
59
 
60
+ SUPERSELF = typing.TypeVar("SUPERSELF", covariant=True)
61
+
60
62
  class Dict(modal.object.Object):
61
63
  def __init__(self, data={}): ...
62
64
  @classmethod
@@ -116,86 +118,86 @@ class Dict(modal.object.Object):
116
118
 
117
119
  delete: __delete_spec
118
120
 
119
- class __clear_spec(typing_extensions.Protocol):
121
+ class __clear_spec(typing_extensions.Protocol[SUPERSELF]):
120
122
  def __call__(self) -> None: ...
121
123
  async def aio(self) -> None: ...
122
124
 
123
- clear: __clear_spec
125
+ clear: __clear_spec[typing_extensions.Self]
124
126
 
125
- class __get_spec(typing_extensions.Protocol):
127
+ class __get_spec(typing_extensions.Protocol[SUPERSELF]):
126
128
  def __call__(self, key: typing.Any, default: typing.Optional[typing.Any] = None) -> typing.Any: ...
127
129
  async def aio(self, key: typing.Any, default: typing.Optional[typing.Any] = None) -> typing.Any: ...
128
130
 
129
- get: __get_spec
131
+ get: __get_spec[typing_extensions.Self]
130
132
 
131
- class __contains_spec(typing_extensions.Protocol):
133
+ class __contains_spec(typing_extensions.Protocol[SUPERSELF]):
132
134
  def __call__(self, key: typing.Any) -> bool: ...
133
135
  async def aio(self, key: typing.Any) -> bool: ...
134
136
 
135
- contains: __contains_spec
137
+ contains: __contains_spec[typing_extensions.Self]
136
138
 
137
- class __len_spec(typing_extensions.Protocol):
139
+ class __len_spec(typing_extensions.Protocol[SUPERSELF]):
138
140
  def __call__(self) -> int: ...
139
141
  async def aio(self) -> int: ...
140
142
 
141
- len: __len_spec
143
+ len: __len_spec[typing_extensions.Self]
142
144
 
143
- class ____getitem___spec(typing_extensions.Protocol):
145
+ class ____getitem___spec(typing_extensions.Protocol[SUPERSELF]):
144
146
  def __call__(self, key: typing.Any) -> typing.Any: ...
145
147
  async def aio(self, key: typing.Any) -> typing.Any: ...
146
148
 
147
- __getitem__: ____getitem___spec
149
+ __getitem__: ____getitem___spec[typing_extensions.Self]
148
150
 
149
- class __update_spec(typing_extensions.Protocol):
151
+ class __update_spec(typing_extensions.Protocol[SUPERSELF]):
150
152
  def __call__(self, **kwargs) -> None: ...
151
153
  async def aio(self, **kwargs) -> None: ...
152
154
 
153
- update: __update_spec
155
+ update: __update_spec[typing_extensions.Self]
154
156
 
155
- class __put_spec(typing_extensions.Protocol):
157
+ class __put_spec(typing_extensions.Protocol[SUPERSELF]):
156
158
  def __call__(self, key: typing.Any, value: typing.Any) -> None: ...
157
159
  async def aio(self, key: typing.Any, value: typing.Any) -> None: ...
158
160
 
159
- put: __put_spec
161
+ put: __put_spec[typing_extensions.Self]
160
162
 
161
- class ____setitem___spec(typing_extensions.Protocol):
163
+ class ____setitem___spec(typing_extensions.Protocol[SUPERSELF]):
162
164
  def __call__(self, key: typing.Any, value: typing.Any) -> None: ...
163
165
  async def aio(self, key: typing.Any, value: typing.Any) -> None: ...
164
166
 
165
- __setitem__: ____setitem___spec
167
+ __setitem__: ____setitem___spec[typing_extensions.Self]
166
168
 
167
- class __pop_spec(typing_extensions.Protocol):
169
+ class __pop_spec(typing_extensions.Protocol[SUPERSELF]):
168
170
  def __call__(self, key: typing.Any) -> typing.Any: ...
169
171
  async def aio(self, key: typing.Any) -> typing.Any: ...
170
172
 
171
- pop: __pop_spec
173
+ pop: __pop_spec[typing_extensions.Self]
172
174
 
173
- class ____delitem___spec(typing_extensions.Protocol):
175
+ class ____delitem___spec(typing_extensions.Protocol[SUPERSELF]):
174
176
  def __call__(self, key: typing.Any) -> typing.Any: ...
175
177
  async def aio(self, key: typing.Any) -> typing.Any: ...
176
178
 
177
- __delitem__: ____delitem___spec
179
+ __delitem__: ____delitem___spec[typing_extensions.Self]
178
180
 
179
- class ____contains___spec(typing_extensions.Protocol):
181
+ class ____contains___spec(typing_extensions.Protocol[SUPERSELF]):
180
182
  def __call__(self, key: typing.Any) -> bool: ...
181
183
  async def aio(self, key: typing.Any) -> bool: ...
182
184
 
183
- __contains__: ____contains___spec
185
+ __contains__: ____contains___spec[typing_extensions.Self]
184
186
 
185
- class __keys_spec(typing_extensions.Protocol):
187
+ class __keys_spec(typing_extensions.Protocol[SUPERSELF]):
186
188
  def __call__(self) -> typing.Iterator[typing.Any]: ...
187
189
  def aio(self) -> collections.abc.AsyncIterator[typing.Any]: ...
188
190
 
189
- keys: __keys_spec
191
+ keys: __keys_spec[typing_extensions.Self]
190
192
 
191
- class __values_spec(typing_extensions.Protocol):
193
+ class __values_spec(typing_extensions.Protocol[SUPERSELF]):
192
194
  def __call__(self) -> typing.Iterator[typing.Any]: ...
193
195
  def aio(self) -> collections.abc.AsyncIterator[typing.Any]: ...
194
196
 
195
- values: __values_spec
197
+ values: __values_spec[typing_extensions.Self]
196
198
 
197
- class __items_spec(typing_extensions.Protocol):
199
+ class __items_spec(typing_extensions.Protocol[SUPERSELF]):
198
200
  def __call__(self) -> typing.Iterator[tuple[typing.Any, typing.Any]]: ...
199
201
  def aio(self) -> collections.abc.AsyncIterator[tuple[typing.Any, typing.Any]]: ...
200
202
 
201
- items: __items_spec
203
+ items: __items_spec[typing_extensions.Self]
modal/file_io.pyi CHANGED
@@ -100,6 +100,8 @@ class __replace_bytes_spec(typing_extensions.Protocol):
100
100
 
101
101
  replace_bytes: __replace_bytes_spec
102
102
 
103
+ SUPERSELF = typing.TypeVar("SUPERSELF", covariant=True)
104
+
103
105
  T_INNER = typing.TypeVar("T_INNER", covariant=True)
104
106
 
105
107
  class FileIO(typing.Generic[T]):
@@ -112,37 +114,37 @@ class FileIO(typing.Generic[T]):
112
114
  def _validate_mode(self, mode: str) -> None: ...
113
115
  def _handle_error(self, error: modal_proto.api_pb2.SystemErrorMessage) -> None: ...
114
116
 
115
- class ___consume_output_spec(typing_extensions.Protocol):
117
+ class ___consume_output_spec(typing_extensions.Protocol[SUPERSELF]):
116
118
  def __call__(self, exec_id: str) -> typing.Iterator[typing.Optional[bytes]]: ...
117
119
  def aio(self, exec_id: str) -> typing.AsyncIterator[typing.Optional[bytes]]: ...
118
120
 
119
- _consume_output: ___consume_output_spec
121
+ _consume_output: ___consume_output_spec[typing_extensions.Self]
120
122
 
121
- class ___consume_watch_output_spec(typing_extensions.Protocol):
123
+ class ___consume_watch_output_spec(typing_extensions.Protocol[SUPERSELF]):
122
124
  def __call__(self, exec_id: str) -> None: ...
123
125
  async def aio(self, exec_id: str) -> None: ...
124
126
 
125
- _consume_watch_output: ___consume_watch_output_spec
127
+ _consume_watch_output: ___consume_watch_output_spec[typing_extensions.Self]
126
128
 
127
- class ___parse_watch_output_spec(typing_extensions.Protocol):
129
+ class ___parse_watch_output_spec(typing_extensions.Protocol[SUPERSELF]):
128
130
  def __call__(self, event: bytes) -> typing.Optional[FileWatchEvent]: ...
129
131
  async def aio(self, event: bytes) -> typing.Optional[FileWatchEvent]: ...
130
132
 
131
- _parse_watch_output: ___parse_watch_output_spec
133
+ _parse_watch_output: ___parse_watch_output_spec[typing_extensions.Self]
132
134
 
133
- class ___wait_spec(typing_extensions.Protocol):
135
+ class ___wait_spec(typing_extensions.Protocol[SUPERSELF]):
134
136
  def __call__(self, exec_id: str) -> bytes: ...
135
137
  async def aio(self, exec_id: str) -> bytes: ...
136
138
 
137
- _wait: ___wait_spec
139
+ _wait: ___wait_spec[typing_extensions.Self]
138
140
 
139
141
  def _validate_type(self, data: typing.Union[bytes, str]) -> None: ...
140
142
 
141
- class ___open_file_spec(typing_extensions.Protocol):
143
+ class ___open_file_spec(typing_extensions.Protocol[SUPERSELF]):
142
144
  def __call__(self, path: str, mode: str) -> None: ...
143
145
  async def aio(self, path: str, mode: str) -> None: ...
144
146
 
145
- _open_file: ___open_file_spec
147
+ _open_file: ___open_file_spec[typing_extensions.Self]
146
148
 
147
149
  @classmethod
148
150
  def create(
@@ -153,49 +155,49 @@ class FileIO(typing.Generic[T]):
153
155
  task_id: str,
154
156
  ) -> FileIO: ...
155
157
 
156
- class ___make_read_request_spec(typing_extensions.Protocol):
158
+ class ___make_read_request_spec(typing_extensions.Protocol[SUPERSELF]):
157
159
  def __call__(self, n: typing.Optional[int]) -> bytes: ...
158
160
  async def aio(self, n: typing.Optional[int]) -> bytes: ...
159
161
 
160
- _make_read_request: ___make_read_request_spec
162
+ _make_read_request: ___make_read_request_spec[typing_extensions.Self]
161
163
 
162
- class __read_spec(typing_extensions.Protocol[T_INNER]):
164
+ class __read_spec(typing_extensions.Protocol[T_INNER, SUPERSELF]):
163
165
  def __call__(self, n: typing.Optional[int] = None) -> T_INNER: ...
164
166
  async def aio(self, n: typing.Optional[int] = None) -> T_INNER: ...
165
167
 
166
- read: __read_spec[T]
168
+ read: __read_spec[T, typing_extensions.Self]
167
169
 
168
- class __readline_spec(typing_extensions.Protocol[T_INNER]):
170
+ class __readline_spec(typing_extensions.Protocol[T_INNER, SUPERSELF]):
169
171
  def __call__(self) -> T_INNER: ...
170
172
  async def aio(self) -> T_INNER: ...
171
173
 
172
- readline: __readline_spec[T]
174
+ readline: __readline_spec[T, typing_extensions.Self]
173
175
 
174
- class __readlines_spec(typing_extensions.Protocol[T_INNER]):
176
+ class __readlines_spec(typing_extensions.Protocol[T_INNER, SUPERSELF]):
175
177
  def __call__(self) -> typing.Sequence[T_INNER]: ...
176
178
  async def aio(self) -> typing.Sequence[T_INNER]: ...
177
179
 
178
- readlines: __readlines_spec[T]
180
+ readlines: __readlines_spec[T, typing_extensions.Self]
179
181
 
180
- class __write_spec(typing_extensions.Protocol):
182
+ class __write_spec(typing_extensions.Protocol[SUPERSELF]):
181
183
  def __call__(self, data: typing.Union[bytes, str]) -> None: ...
182
184
  async def aio(self, data: typing.Union[bytes, str]) -> None: ...
183
185
 
184
- write: __write_spec
186
+ write: __write_spec[typing_extensions.Self]
185
187
 
186
- class __flush_spec(typing_extensions.Protocol):
188
+ class __flush_spec(typing_extensions.Protocol[SUPERSELF]):
187
189
  def __call__(self) -> None: ...
188
190
  async def aio(self) -> None: ...
189
191
 
190
- flush: __flush_spec
192
+ flush: __flush_spec[typing_extensions.Self]
191
193
 
192
194
  def _get_whence(self, whence: int): ...
193
195
 
194
- class __seek_spec(typing_extensions.Protocol):
196
+ class __seek_spec(typing_extensions.Protocol[SUPERSELF]):
195
197
  def __call__(self, offset: int, whence: int = 0) -> None: ...
196
198
  async def aio(self, offset: int, whence: int = 0) -> None: ...
197
199
 
198
- seek: __seek_spec
200
+ seek: __seek_spec[typing_extensions.Self]
199
201
 
200
202
  @classmethod
201
203
  def ls(cls, path: str, client: modal.client.Client, task_id: str) -> list[str]: ...
@@ -214,17 +216,17 @@ class FileIO(typing.Generic[T]):
214
216
  timeout: typing.Optional[int] = None,
215
217
  ) -> typing.Iterator[FileWatchEvent]: ...
216
218
 
217
- class ___close_spec(typing_extensions.Protocol):
219
+ class ___close_spec(typing_extensions.Protocol[SUPERSELF]):
218
220
  def __call__(self) -> None: ...
219
221
  async def aio(self) -> None: ...
220
222
 
221
- _close: ___close_spec
223
+ _close: ___close_spec[typing_extensions.Self]
222
224
 
223
- class __close_spec(typing_extensions.Protocol):
225
+ class __close_spec(typing_extensions.Protocol[SUPERSELF]):
224
226
  def __call__(self) -> None: ...
225
227
  async def aio(self) -> None: ...
226
228
 
227
- close: __close_spec
229
+ close: __close_spec[typing_extensions.Self]
228
230
 
229
231
  def _check_writable(self) -> None: ...
230
232
  def _check_readable(self) -> None: ...
modal/functions.py CHANGED
@@ -1207,12 +1207,13 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
1207
1207
  async def is_generator(self) -> bool:
1208
1208
  """mdmd:hidden"""
1209
1209
  # hacky: kind of like @live_method, but not hydrating if we have the value already from local source
1210
+ # TODO(michael) use a common / lightweight method for handling unhydrated metadata properties
1210
1211
  if self._is_generator is not None:
1211
1212
  # this is set if the function or class is local
1212
1213
  return self._is_generator
1213
1214
 
1214
1215
  # not set - this is a from_name lookup - hydrate
1215
- await self.resolve()
1216
+ await self.hydrate()
1216
1217
  assert self._is_generator is not None # should be set now
1217
1218
  return self._is_generator
1218
1219