modal 0.72.4__py3-none-any.whl → 0.72.48__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.
Files changed (73) hide show
  1. modal/_container_entrypoint.py +5 -10
  2. modal/_object.py +297 -0
  3. modal/_resolver.py +7 -5
  4. modal/_runtime/container_io_manager.py +0 -11
  5. modal/_runtime/user_code_imports.py +7 -7
  6. modal/_serialization.py +4 -3
  7. modal/_tunnel.py +1 -1
  8. modal/app.py +14 -61
  9. modal/app.pyi +25 -25
  10. modal/cli/app.py +3 -2
  11. modal/cli/container.py +1 -1
  12. modal/cli/import_refs.py +185 -113
  13. modal/cli/launch.py +10 -5
  14. modal/cli/programs/run_jupyter.py +2 -2
  15. modal/cli/programs/vscode.py +3 -3
  16. modal/cli/run.py +134 -68
  17. modal/client.py +1 -0
  18. modal/client.pyi +18 -14
  19. modal/cloud_bucket_mount.py +4 -0
  20. modal/cloud_bucket_mount.pyi +4 -0
  21. modal/cls.py +33 -5
  22. modal/cls.pyi +20 -5
  23. modal/container_process.pyi +8 -6
  24. modal/dict.py +1 -1
  25. modal/dict.pyi +32 -29
  26. modal/environments.py +1 -1
  27. modal/environments.pyi +2 -1
  28. modal/experimental.py +47 -11
  29. modal/experimental.pyi +29 -0
  30. modal/file_io.pyi +30 -28
  31. modal/file_pattern_matcher.py +32 -25
  32. modal/functions.py +31 -23
  33. modal/functions.pyi +57 -50
  34. modal/gpu.py +19 -26
  35. modal/image.py +47 -19
  36. modal/image.pyi +28 -21
  37. modal/io_streams.pyi +14 -12
  38. modal/mount.py +14 -5
  39. modal/mount.pyi +28 -25
  40. modal/network_file_system.py +7 -7
  41. modal/network_file_system.pyi +27 -24
  42. modal/object.py +2 -265
  43. modal/object.pyi +46 -130
  44. modal/parallel_map.py +2 -2
  45. modal/parallel_map.pyi +10 -7
  46. modal/partial_function.py +22 -3
  47. modal/partial_function.pyi +45 -27
  48. modal/proxy.py +1 -1
  49. modal/proxy.pyi +2 -1
  50. modal/queue.py +1 -1
  51. modal/queue.pyi +26 -23
  52. modal/runner.py +14 -3
  53. modal/sandbox.py +11 -7
  54. modal/sandbox.pyi +30 -27
  55. modal/secret.py +1 -1
  56. modal/secret.pyi +2 -1
  57. modal/token_flow.pyi +6 -4
  58. modal/volume.py +1 -1
  59. modal/volume.pyi +36 -33
  60. {modal-0.72.4.dist-info → modal-0.72.48.dist-info}/METADATA +2 -2
  61. {modal-0.72.4.dist-info → modal-0.72.48.dist-info}/RECORD +73 -71
  62. modal_proto/api.proto +151 -4
  63. modal_proto/api_grpc.py +113 -0
  64. modal_proto/api_pb2.py +998 -795
  65. modal_proto/api_pb2.pyi +430 -11
  66. modal_proto/api_pb2_grpc.py +233 -1
  67. modal_proto/api_pb2_grpc.pyi +75 -3
  68. modal_proto/modal_api_grpc.py +7 -0
  69. modal_version/_version_generated.py +1 -1
  70. {modal-0.72.4.dist-info → modal-0.72.48.dist-info}/LICENSE +0 -0
  71. {modal-0.72.4.dist-info → modal-0.72.48.dist-info}/WHEEL +0 -0
  72. {modal-0.72.4.dist-info → modal-0.72.48.dist-info}/entry_points.txt +0 -0
  73. {modal-0.72.4.dist-info → modal-0.72.48.dist-info}/top_level.txt +0 -0
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: ...
@@ -84,6 +85,8 @@ class _Queue(modal.object._Object):
84
85
  self, *, partition: typing.Optional[str] = None, item_poll_timeout: float = 0.0
85
86
  ) -> collections.abc.AsyncGenerator[typing.Any, None]: ...
86
87
 
88
+ SUPERSELF = typing.TypeVar("SUPERSELF", covariant=True)
89
+
87
90
  class Queue(modal.object.Object):
88
91
  def __init__(self): ...
89
92
  @staticmethod
@@ -138,13 +141,13 @@ class Queue(modal.object.Object):
138
141
 
139
142
  delete: __delete_spec
140
143
 
141
- class ___get_nonblocking_spec(typing_extensions.Protocol):
144
+ class ___get_nonblocking_spec(typing_extensions.Protocol[SUPERSELF]):
142
145
  def __call__(self, partition: typing.Optional[str], n_values: int) -> list[typing.Any]: ...
143
146
  async def aio(self, partition: typing.Optional[str], n_values: int) -> list[typing.Any]: ...
144
147
 
145
- _get_nonblocking: ___get_nonblocking_spec
148
+ _get_nonblocking: ___get_nonblocking_spec[typing_extensions.Self]
146
149
 
147
- class ___get_blocking_spec(typing_extensions.Protocol):
150
+ class ___get_blocking_spec(typing_extensions.Protocol[SUPERSELF]):
148
151
  def __call__(
149
152
  self, partition: typing.Optional[str], timeout: typing.Optional[float], n_values: int
150
153
  ) -> list[typing.Any]: ...
@@ -152,15 +155,15 @@ class Queue(modal.object.Object):
152
155
  self, partition: typing.Optional[str], timeout: typing.Optional[float], n_values: int
153
156
  ) -> list[typing.Any]: ...
154
157
 
155
- _get_blocking: ___get_blocking_spec
158
+ _get_blocking: ___get_blocking_spec[typing_extensions.Self]
156
159
 
157
- class __clear_spec(typing_extensions.Protocol):
160
+ class __clear_spec(typing_extensions.Protocol[SUPERSELF]):
158
161
  def __call__(self, *, partition: typing.Optional[str] = None, all: bool = False) -> None: ...
159
162
  async def aio(self, *, partition: typing.Optional[str] = None, all: bool = False) -> None: ...
160
163
 
161
- clear: __clear_spec
164
+ clear: __clear_spec[typing_extensions.Self]
162
165
 
163
- class __get_spec(typing_extensions.Protocol):
166
+ class __get_spec(typing_extensions.Protocol[SUPERSELF]):
164
167
  def __call__(
165
168
  self, block: bool = True, timeout: typing.Optional[float] = None, *, partition: typing.Optional[str] = None
166
169
  ) -> typing.Optional[typing.Any]: ...
@@ -168,9 +171,9 @@ class Queue(modal.object.Object):
168
171
  self, block: bool = True, timeout: typing.Optional[float] = None, *, partition: typing.Optional[str] = None
169
172
  ) -> typing.Optional[typing.Any]: ...
170
173
 
171
- get: __get_spec
174
+ get: __get_spec[typing_extensions.Self]
172
175
 
173
- class __get_many_spec(typing_extensions.Protocol):
176
+ class __get_many_spec(typing_extensions.Protocol[SUPERSELF]):
174
177
  def __call__(
175
178
  self,
176
179
  n_values: int,
@@ -188,9 +191,9 @@ class Queue(modal.object.Object):
188
191
  partition: typing.Optional[str] = None,
189
192
  ) -> list[typing.Any]: ...
190
193
 
191
- get_many: __get_many_spec
194
+ get_many: __get_many_spec[typing_extensions.Self]
192
195
 
193
- class __put_spec(typing_extensions.Protocol):
196
+ class __put_spec(typing_extensions.Protocol[SUPERSELF]):
194
197
  def __call__(
195
198
  self,
196
199
  v: typing.Any,
@@ -210,9 +213,9 @@ class Queue(modal.object.Object):
210
213
  partition_ttl: int = 86400,
211
214
  ) -> None: ...
212
215
 
213
- put: __put_spec
216
+ put: __put_spec[typing_extensions.Self]
214
217
 
215
- class __put_many_spec(typing_extensions.Protocol):
218
+ class __put_many_spec(typing_extensions.Protocol[SUPERSELF]):
216
219
  def __call__(
217
220
  self,
218
221
  vs: list[typing.Any],
@@ -232,9 +235,9 @@ class Queue(modal.object.Object):
232
235
  partition_ttl: int = 86400,
233
236
  ) -> None: ...
234
237
 
235
- put_many: __put_many_spec
238
+ put_many: __put_many_spec[typing_extensions.Self]
236
239
 
237
- class ___put_many_blocking_spec(typing_extensions.Protocol):
240
+ class ___put_many_blocking_spec(typing_extensions.Protocol[SUPERSELF]):
238
241
  def __call__(
239
242
  self,
240
243
  partition: typing.Optional[str],
@@ -250,21 +253,21 @@ class Queue(modal.object.Object):
250
253
  timeout: typing.Optional[float] = None,
251
254
  ): ...
252
255
 
253
- _put_many_blocking: ___put_many_blocking_spec
256
+ _put_many_blocking: ___put_many_blocking_spec[typing_extensions.Self]
254
257
 
255
- class ___put_many_nonblocking_spec(typing_extensions.Protocol):
258
+ class ___put_many_nonblocking_spec(typing_extensions.Protocol[SUPERSELF]):
256
259
  def __call__(self, partition: typing.Optional[str], partition_ttl: int, vs: list[typing.Any]): ...
257
260
  async def aio(self, partition: typing.Optional[str], partition_ttl: int, vs: list[typing.Any]): ...
258
261
 
259
- _put_many_nonblocking: ___put_many_nonblocking_spec
262
+ _put_many_nonblocking: ___put_many_nonblocking_spec[typing_extensions.Self]
260
263
 
261
- class __len_spec(typing_extensions.Protocol):
264
+ class __len_spec(typing_extensions.Protocol[SUPERSELF]):
262
265
  def __call__(self, *, partition: typing.Optional[str] = None, total: bool = False) -> int: ...
263
266
  async def aio(self, *, partition: typing.Optional[str] = None, total: bool = False) -> int: ...
264
267
 
265
- len: __len_spec
268
+ len: __len_spec[typing_extensions.Self]
266
269
 
267
- class __iterate_spec(typing_extensions.Protocol):
270
+ class __iterate_spec(typing_extensions.Protocol[SUPERSELF]):
268
271
  def __call__(
269
272
  self, *, partition: typing.Optional[str] = None, item_poll_timeout: float = 0.0
270
273
  ) -> typing.Generator[typing.Any, None, None]: ...
@@ -272,4 +275,4 @@ class Queue(modal.object.Object):
272
275
  self, *, partition: typing.Optional[str] = None, item_poll_timeout: float = 0.0
273
276
  ) -> collections.abc.AsyncGenerator[typing.Any, None]: ...
274
277
 
275
- iterate: __iterate_spec
278
+ iterate: __iterate_spec[typing_extensions.Self]
modal/runner.py CHANGED
@@ -4,6 +4,7 @@ import dataclasses
4
4
  import os
5
5
  import time
6
6
  import typing
7
+ import warnings
7
8
  from collections.abc import AsyncGenerator
8
9
  from multiprocessing.synchronize import Event
9
10
  from typing import TYPE_CHECKING, Any, Optional, TypeVar
@@ -14,6 +15,7 @@ from synchronicity.async_wrap import asynccontextmanager
14
15
  import modal_proto.api_pb2
15
16
  from modal_proto import api_pb2
16
17
 
18
+ from ._object import _get_environment_name, _Object
17
19
  from ._pty import get_pty_info
18
20
  from ._resolver import Resolver
19
21
  from ._runtime.execution_context import is_local
@@ -28,7 +30,6 @@ from .config import config, logger
28
30
  from .environments import _get_environment_cached
29
31
  from .exception import InteractiveTimeoutError, InvalidError, RemoteError, _CliUserExecutionError
30
32
  from .functions import _Function
31
- from .object import _get_environment_name, _Object
32
33
  from .output import _get_output_manager, enable_output
33
34
  from .running_app import RunningApp, running_app_from_layout
34
35
  from .sandbox import _Sandbox
@@ -155,7 +156,7 @@ async def _create_all_objects(
155
156
  # this is to ensure that directly referenced functions from the global scope has
156
157
  # ids associated with them when they are serialized into other functions
157
158
  await resolver.preload(obj, existing_object_id)
158
- if obj.object_id is not None:
159
+ if obj.is_hydrated:
159
160
  tag_to_object_id[tag] = obj.object_id
160
161
 
161
162
  await TaskContext.gather(*(_preload(tag, obj) for tag, obj in indexed_objects.items()))
@@ -287,6 +288,16 @@ async def _run_app(
287
288
  client = await _Client.from_env()
288
289
 
289
290
  app_state = api_pb2.APP_STATE_DETACHED if detach else api_pb2.APP_STATE_EPHEMERAL
291
+
292
+ output_mgr = _get_output_manager()
293
+ if interactive and output_mgr is None:
294
+ warnings.warn(
295
+ "Interactive mode is disabled because no output manager is active. "
296
+ "Use 'with modal.enable_output():' to enable interactive mode and see logs.",
297
+ stacklevel=2,
298
+ )
299
+ interactive = False
300
+
290
301
  running_app: RunningApp = await _init_local_app_new(
291
302
  client,
292
303
  app.description or "",
@@ -306,7 +317,7 @@ async def _run_app(
306
317
  tc.infinite_loop(heartbeat, sleep=HEARTBEAT_INTERVAL, log_exception=not detach)
307
318
  logs_loop: Optional[asyncio.Task] = None
308
319
 
309
- if output_mgr := _get_output_manager():
320
+ if output_mgr is not None:
310
321
  # Defer import so this module is rich-safe
311
322
  # TODO(michael): The get_app_logs_loop function is itself rich-safe aside from accepting an OutputManager
312
323
  # as an argument, so with some refactoring we could avoid the need for this deferred import.
modal/sandbox.py CHANGED
@@ -16,9 +16,10 @@ 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
- from ._utils.async_utils import synchronize_api
22
+ from ._utils.async_utils import TaskContext, synchronize_api
22
23
  from ._utils.deprecation import deprecation_error
23
24
  from ._utils.grpc_utils import retry_transient_errors
24
25
  from ._utils.mount_utils import validate_network_file_systems, validate_volumes
@@ -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
@@ -165,7 +165,8 @@ class _Sandbox(_Object, type_prefix="sb"):
165
165
  resources=convert_fn_config_to_resources_config(
166
166
  cpu=cpu, memory=memory, gpu=gpu, ephemeral_disk=ephemeral_disk
167
167
  ),
168
- cloud_provider=parse_cloud_provider(cloud) if cloud else None,
168
+ cloud_provider=parse_cloud_provider(cloud) if cloud else None, # Deprecated at some point
169
+ cloud_provider_str=cloud.upper() if cloud else None, # Supersedes cloud_provider
169
170
  nfs_mounts=network_file_system_mount_protos(validated_network_file_systems, False),
170
171
  runtime_debug=config.get("function_runtime_debug"),
171
172
  cloud_bucket_mounts=cloud_bucket_mounts_to_proto(cloud_bucket_mounts),
@@ -350,6 +351,7 @@ class _Sandbox(_Object, type_prefix="sb"):
350
351
  Returns an [`Image`](https://modal.com/docs/reference/modal.Image) object which
351
352
  can be used to spawn a new Sandbox with the same filesystem.
352
353
  """
354
+ await self._get_task_id() # Ensure the sandbox has started
353
355
  req = api_pb2.SandboxSnapshotFsRequest(sandbox_id=self.object_id, timeout=timeout)
354
356
  resp = await retry_transient_errors(self._client.stub.SandboxSnapshotFs, req)
355
357
 
@@ -360,10 +362,12 @@ class _Sandbox(_Object, type_prefix="sb"):
360
362
  metadata = resp.image_metadata
361
363
 
362
364
  async def _load(self: _Image, resolver: Resolver, existing_object_id: Optional[str]):
363
- self._hydrate(image_id, resolver.client, metadata)
365
+ # no need to hydrate again since we do it eagerly below
366
+ pass
364
367
 
365
368
  rep = "Image()"
366
- image = _Image._from_loader(_load, rep)
369
+ image = _Image._from_loader(_load, rep, hydrate_lazily=True)
370
+ image._hydrate(image_id, self._client, metadata) # hydrating eagerly since we have all of the data
367
371
 
368
372
  return image
369
373
 
@@ -513,8 +517,8 @@ class _Sandbox(_Object, type_prefix="sb"):
513
517
  raise InvalidError(f"workdir must be an absolute path, got: {workdir}")
514
518
 
515
519
  # Force secret resolution so we can pass the secret IDs to the backend.
516
- for secret in secrets:
517
- await secret.resolve(client=self._client)
520
+ secret_coros = [secret.hydrate(client=self._client) for secret in secrets]
521
+ await TaskContext.gather(*secret_coros)
518
522
 
519
523
  task_id = await self._get_task_id()
520
524
  req = api_pb2.ContainerExecRequest(
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]
@@ -154,6 +155,8 @@ class _Sandbox(modal.object._Object):
154
155
  client: typing.Optional[modal.client._Client] = None,
155
156
  ) -> collections.abc.AsyncGenerator[_Sandbox, None]: ...
156
157
 
158
+ SUPERSELF = typing.TypeVar("SUPERSELF", covariant=True)
159
+
157
160
  class Sandbox(modal.object.Object):
158
161
  _result: typing.Optional[modal_proto.api_pb2.GenericResult]
159
162
  _stdout: modal.io_streams.StreamReader[str]
@@ -263,49 +266,49 @@ class Sandbox(modal.object.Object):
263
266
 
264
267
  from_id: __from_id_spec
265
268
 
266
- class __set_tags_spec(typing_extensions.Protocol):
269
+ class __set_tags_spec(typing_extensions.Protocol[SUPERSELF]):
267
270
  def __call__(self, tags: dict[str, str], *, client: typing.Optional[modal.client.Client] = None): ...
268
271
  async def aio(self, tags: dict[str, str], *, client: typing.Optional[modal.client.Client] = None): ...
269
272
 
270
- set_tags: __set_tags_spec
273
+ set_tags: __set_tags_spec[typing_extensions.Self]
271
274
 
272
- class __snapshot_filesystem_spec(typing_extensions.Protocol):
275
+ class __snapshot_filesystem_spec(typing_extensions.Protocol[SUPERSELF]):
273
276
  def __call__(self, timeout: int = 55) -> modal.image.Image: ...
274
277
  async def aio(self, timeout: int = 55) -> modal.image.Image: ...
275
278
 
276
- snapshot_filesystem: __snapshot_filesystem_spec
279
+ snapshot_filesystem: __snapshot_filesystem_spec[typing_extensions.Self]
277
280
 
278
- class __wait_spec(typing_extensions.Protocol):
281
+ class __wait_spec(typing_extensions.Protocol[SUPERSELF]):
279
282
  def __call__(self, raise_on_termination: bool = True): ...
280
283
  async def aio(self, raise_on_termination: bool = True): ...
281
284
 
282
- wait: __wait_spec
285
+ wait: __wait_spec[typing_extensions.Self]
283
286
 
284
- class __tunnels_spec(typing_extensions.Protocol):
287
+ class __tunnels_spec(typing_extensions.Protocol[SUPERSELF]):
285
288
  def __call__(self, timeout: int = 50) -> dict[int, modal._tunnel.Tunnel]: ...
286
289
  async def aio(self, timeout: int = 50) -> dict[int, modal._tunnel.Tunnel]: ...
287
290
 
288
- tunnels: __tunnels_spec
291
+ tunnels: __tunnels_spec[typing_extensions.Self]
289
292
 
290
- class __terminate_spec(typing_extensions.Protocol):
293
+ class __terminate_spec(typing_extensions.Protocol[SUPERSELF]):
291
294
  def __call__(self): ...
292
295
  async def aio(self): ...
293
296
 
294
- terminate: __terminate_spec
297
+ terminate: __terminate_spec[typing_extensions.Self]
295
298
 
296
- class __poll_spec(typing_extensions.Protocol):
299
+ class __poll_spec(typing_extensions.Protocol[SUPERSELF]):
297
300
  def __call__(self) -> typing.Optional[int]: ...
298
301
  async def aio(self) -> typing.Optional[int]: ...
299
302
 
300
- poll: __poll_spec
303
+ poll: __poll_spec[typing_extensions.Self]
301
304
 
302
- class ___get_task_id_spec(typing_extensions.Protocol):
305
+ class ___get_task_id_spec(typing_extensions.Protocol[SUPERSELF]):
303
306
  def __call__(self): ...
304
307
  async def aio(self): ...
305
308
 
306
- _get_task_id: ___get_task_id_spec
309
+ _get_task_id: ___get_task_id_spec[typing_extensions.Self]
307
310
 
308
- class __exec_spec(typing_extensions.Protocol):
311
+ class __exec_spec(typing_extensions.Protocol[SUPERSELF]):
309
312
  @typing.overload
310
313
  def __call__(
311
314
  self,
@@ -363,9 +366,9 @@ class Sandbox(modal.object.Object):
363
366
  _pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
364
367
  ) -> modal.container_process.ContainerProcess[bytes]: ...
365
368
 
366
- exec: __exec_spec
369
+ exec: __exec_spec[typing_extensions.Self]
367
370
 
368
- class __open_spec(typing_extensions.Protocol):
371
+ class __open_spec(typing_extensions.Protocol[SUPERSELF]):
369
372
  @typing.overload
370
373
  def __call__(self, path: str, mode: _typeshed.OpenTextMode) -> modal.file_io.FileIO[str]: ...
371
374
  @typing.overload
@@ -375,27 +378,27 @@ class Sandbox(modal.object.Object):
375
378
  @typing.overload
376
379
  async def aio(self, path: str, mode: _typeshed.OpenBinaryMode) -> modal.file_io.FileIO[bytes]: ...
377
380
 
378
- open: __open_spec
381
+ open: __open_spec[typing_extensions.Self]
379
382
 
380
- class __ls_spec(typing_extensions.Protocol):
383
+ class __ls_spec(typing_extensions.Protocol[SUPERSELF]):
381
384
  def __call__(self, path: str) -> list[str]: ...
382
385
  async def aio(self, path: str) -> list[str]: ...
383
386
 
384
- ls: __ls_spec
387
+ ls: __ls_spec[typing_extensions.Self]
385
388
 
386
- class __mkdir_spec(typing_extensions.Protocol):
389
+ class __mkdir_spec(typing_extensions.Protocol[SUPERSELF]):
387
390
  def __call__(self, path: str, parents: bool = False) -> None: ...
388
391
  async def aio(self, path: str, parents: bool = False) -> None: ...
389
392
 
390
- mkdir: __mkdir_spec
393
+ mkdir: __mkdir_spec[typing_extensions.Self]
391
394
 
392
- class __rm_spec(typing_extensions.Protocol):
395
+ class __rm_spec(typing_extensions.Protocol[SUPERSELF]):
393
396
  def __call__(self, path: str, recursive: bool = False) -> None: ...
394
397
  async def aio(self, path: str, recursive: bool = False) -> None: ...
395
398
 
396
- rm: __rm_spec
399
+ rm: __rm_spec[typing_extensions.Self]
397
400
 
398
- class __watch_spec(typing_extensions.Protocol):
401
+ class __watch_spec(typing_extensions.Protocol[SUPERSELF]):
399
402
  def __call__(
400
403
  self,
401
404
  path: str,
@@ -411,7 +414,7 @@ class Sandbox(modal.object.Object):
411
414
  timeout: typing.Optional[int] = None,
412
415
  ) -> typing.AsyncIterator[modal.file_io.FileWatchEvent]: ...
413
416
 
414
- watch: __watch_spec
417
+ watch: __watch_spec[typing_extensions.Self]
415
418
 
416
419
  @property
417
420
  def stdout(self) -> 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/token_flow.pyi CHANGED
@@ -13,10 +13,12 @@ class _TokenFlow:
13
13
  self, timeout: float = 40.0, grpc_extra_timeout: float = 5.0
14
14
  ) -> typing.Optional[modal_proto.api_pb2.TokenFlowWaitResponse]: ...
15
15
 
16
+ SUPERSELF = typing.TypeVar("SUPERSELF", covariant=True)
17
+
16
18
  class TokenFlow:
17
19
  def __init__(self, client: modal.client.Client): ...
18
20
 
19
- class __start_spec(typing_extensions.Protocol):
21
+ class __start_spec(typing_extensions.Protocol[SUPERSELF]):
20
22
  def __call__(
21
23
  self, utm_source: typing.Optional[str] = None, next_url: typing.Optional[str] = None
22
24
  ) -> synchronicity.combined_types.AsyncAndBlockingContextManager[tuple[str, str, str]]: ...
@@ -24,9 +26,9 @@ class TokenFlow:
24
26
  self, utm_source: typing.Optional[str] = None, next_url: typing.Optional[str] = None
25
27
  ) -> typing.AsyncContextManager[tuple[str, str, str]]: ...
26
28
 
27
- start: __start_spec
29
+ start: __start_spec[typing_extensions.Self]
28
30
 
29
- class __finish_spec(typing_extensions.Protocol):
31
+ class __finish_spec(typing_extensions.Protocol[SUPERSELF]):
30
32
  def __call__(
31
33
  self, timeout: float = 40.0, grpc_extra_timeout: float = 5.0
32
34
  ) -> typing.Optional[modal_proto.api_pb2.TokenFlowWaitResponse]: ...
@@ -34,7 +36,7 @@ class TokenFlow:
34
36
  self, timeout: float = 40.0, grpc_extra_timeout: float = 5.0
35
37
  ) -> typing.Optional[modal_proto.api_pb2.TokenFlowWaitResponse]: ...
36
38
 
37
- finish: __finish_spec
39
+ finish: __finish_spec[typing_extensions.Self]
38
40
 
39
41
  async def _new_token(
40
42
  *,
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): ...
@@ -98,16 +99,16 @@ class _VolumeUploadContextManager:
98
99
  _volume_id: str
99
100
  _client: modal.client._Client
100
101
  _force: bool
101
- progress_cb: typing.Callable[..., typing.Any]
102
+ progress_cb: collections.abc.Callable[..., typing.Any]
102
103
  _upload_generators: list[
103
- collections.abc.Generator[typing.Callable[[], modal._utils.blob_utils.FileUploadSpec], None, None]
104
+ collections.abc.Generator[collections.abc.Callable[[], modal._utils.blob_utils.FileUploadSpec], None, None]
104
105
  ]
105
106
 
106
107
  def __init__(
107
108
  self,
108
109
  volume_id: str,
109
110
  client: modal.client._Client,
110
- progress_cb: typing.Optional[typing.Callable[..., typing.Any]] = None,
111
+ progress_cb: typing.Optional[collections.abc.Callable[..., typing.Any]] = None,
111
112
  force: bool = False,
112
113
  ): ...
113
114
  async def __aenter__(self): ...
@@ -128,16 +129,18 @@ class _VolumeUploadContextManager:
128
129
  self, file_spec: modal._utils.blob_utils.FileUploadSpec
129
130
  ) -> modal_proto.api_pb2.MountFile: ...
130
131
 
132
+ SUPERSELF = typing.TypeVar("SUPERSELF", covariant=True)
133
+
131
134
  class Volume(modal.object.Object):
132
135
  _lock: typing.Optional[asyncio.locks.Lock]
133
136
 
134
137
  def __init__(self, *args, **kwargs): ...
135
138
 
136
- class ___get_lock_spec(typing_extensions.Protocol):
139
+ class ___get_lock_spec(typing_extensions.Protocol[SUPERSELF]):
137
140
  def __call__(self): ...
138
141
  async def aio(self): ...
139
142
 
140
- _get_lock: ___get_lock_spec
143
+ _get_lock: ___get_lock_spec[typing_extensions.Self]
141
144
 
142
145
  @staticmethod
143
146
  def from_name(
@@ -198,71 +201,71 @@ class Volume(modal.object.Object):
198
201
 
199
202
  create_deployed: __create_deployed_spec
200
203
 
201
- class ___do_reload_spec(typing_extensions.Protocol):
204
+ class ___do_reload_spec(typing_extensions.Protocol[SUPERSELF]):
202
205
  def __call__(self, lock=True): ...
203
206
  async def aio(self, lock=True): ...
204
207
 
205
- _do_reload: ___do_reload_spec
208
+ _do_reload: ___do_reload_spec[typing_extensions.Self]
206
209
 
207
- class __commit_spec(typing_extensions.Protocol):
210
+ class __commit_spec(typing_extensions.Protocol[SUPERSELF]):
208
211
  def __call__(self): ...
209
212
  async def aio(self): ...
210
213
 
211
- commit: __commit_spec
214
+ commit: __commit_spec[typing_extensions.Self]
212
215
 
213
- class __reload_spec(typing_extensions.Protocol):
216
+ class __reload_spec(typing_extensions.Protocol[SUPERSELF]):
214
217
  def __call__(self): ...
215
218
  async def aio(self): ...
216
219
 
217
- reload: __reload_spec
220
+ reload: __reload_spec[typing_extensions.Self]
218
221
 
219
- class __iterdir_spec(typing_extensions.Protocol):
222
+ class __iterdir_spec(typing_extensions.Protocol[SUPERSELF]):
220
223
  def __call__(self, path: str, *, recursive: bool = True) -> typing.Iterator[FileEntry]: ...
221
224
  def aio(self, path: str, *, recursive: bool = True) -> collections.abc.AsyncIterator[FileEntry]: ...
222
225
 
223
- iterdir: __iterdir_spec
226
+ iterdir: __iterdir_spec[typing_extensions.Self]
224
227
 
225
- class __listdir_spec(typing_extensions.Protocol):
228
+ class __listdir_spec(typing_extensions.Protocol[SUPERSELF]):
226
229
  def __call__(self, path: str, *, recursive: bool = False) -> list[FileEntry]: ...
227
230
  async def aio(self, path: str, *, recursive: bool = False) -> list[FileEntry]: ...
228
231
 
229
- listdir: __listdir_spec
232
+ listdir: __listdir_spec[typing_extensions.Self]
230
233
 
231
- class __read_file_spec(typing_extensions.Protocol):
234
+ class __read_file_spec(typing_extensions.Protocol[SUPERSELF]):
232
235
  def __call__(self, path: str) -> typing.Iterator[bytes]: ...
233
236
  def aio(self, path: str) -> collections.abc.AsyncIterator[bytes]: ...
234
237
 
235
- read_file: __read_file_spec
238
+ read_file: __read_file_spec[typing_extensions.Self]
236
239
 
237
- class __read_file_into_fileobj_spec(typing_extensions.Protocol):
240
+ class __read_file_into_fileobj_spec(typing_extensions.Protocol[SUPERSELF]):
238
241
  def __call__(self, path: str, fileobj: typing.IO[bytes]) -> int: ...
239
242
  async def aio(self, path: str, fileobj: typing.IO[bytes]) -> int: ...
240
243
 
241
- read_file_into_fileobj: __read_file_into_fileobj_spec
244
+ read_file_into_fileobj: __read_file_into_fileobj_spec[typing_extensions.Self]
242
245
 
243
- class __remove_file_spec(typing_extensions.Protocol):
246
+ class __remove_file_spec(typing_extensions.Protocol[SUPERSELF]):
244
247
  def __call__(self, path: str, recursive: bool = False) -> None: ...
245
248
  async def aio(self, path: str, recursive: bool = False) -> None: ...
246
249
 
247
- remove_file: __remove_file_spec
250
+ remove_file: __remove_file_spec[typing_extensions.Self]
248
251
 
249
- class __copy_files_spec(typing_extensions.Protocol):
252
+ class __copy_files_spec(typing_extensions.Protocol[SUPERSELF]):
250
253
  def __call__(self, src_paths: collections.abc.Sequence[str], dst_path: str) -> None: ...
251
254
  async def aio(self, src_paths: collections.abc.Sequence[str], dst_path: str) -> None: ...
252
255
 
253
- copy_files: __copy_files_spec
256
+ copy_files: __copy_files_spec[typing_extensions.Self]
254
257
 
255
- class __batch_upload_spec(typing_extensions.Protocol):
258
+ class __batch_upload_spec(typing_extensions.Protocol[SUPERSELF]):
256
259
  def __call__(self, force: bool = False) -> VolumeUploadContextManager: ...
257
260
  async def aio(self, force: bool = False) -> VolumeUploadContextManager: ...
258
261
 
259
- batch_upload: __batch_upload_spec
262
+ batch_upload: __batch_upload_spec[typing_extensions.Self]
260
263
 
261
- class ___instance_delete_spec(typing_extensions.Protocol):
264
+ class ___instance_delete_spec(typing_extensions.Protocol[SUPERSELF]):
262
265
  def __call__(self): ...
263
266
  async def aio(self): ...
264
267
 
265
- _instance_delete: ___instance_delete_spec
268
+ _instance_delete: ___instance_delete_spec[typing_extensions.Self]
266
269
 
267
270
  class __delete_spec(typing_extensions.Protocol):
268
271
  def __call__(
@@ -304,16 +307,16 @@ class VolumeUploadContextManager:
304
307
  _volume_id: str
305
308
  _client: modal.client.Client
306
309
  _force: bool
307
- progress_cb: typing.Callable[..., typing.Any]
310
+ progress_cb: collections.abc.Callable[..., typing.Any]
308
311
  _upload_generators: list[
309
- collections.abc.Generator[typing.Callable[[], modal._utils.blob_utils.FileUploadSpec], None, None]
312
+ collections.abc.Generator[collections.abc.Callable[[], modal._utils.blob_utils.FileUploadSpec], None, None]
310
313
  ]
311
314
 
312
315
  def __init__(
313
316
  self,
314
317
  volume_id: str,
315
318
  client: modal.client.Client,
316
- progress_cb: typing.Optional[typing.Callable[..., typing.Any]] = None,
319
+ progress_cb: typing.Optional[collections.abc.Callable[..., typing.Any]] = None,
317
320
  force: bool = False,
318
321
  ): ...
319
322
  def __enter__(self): ...
@@ -333,10 +336,10 @@ class VolumeUploadContextManager:
333
336
  recursive: bool = True,
334
337
  ): ...
335
338
 
336
- class ___upload_file_spec(typing_extensions.Protocol):
339
+ class ___upload_file_spec(typing_extensions.Protocol[SUPERSELF]):
337
340
  def __call__(self, file_spec: modal._utils.blob_utils.FileUploadSpec) -> modal_proto.api_pb2.MountFile: ...
338
341
  async def aio(self, file_spec: modal._utils.blob_utils.FileUploadSpec) -> modal_proto.api_pb2.MountFile: ...
339
342
 
340
- _upload_file: ___upload_file_spec
343
+ _upload_file: ___upload_file_spec[typing_extensions.Self]
341
344
 
342
345
  def _open_files_error_annotation(mount_path: str) -> typing.Optional[str]: ...