modal 1.1.5.dev83__py3-none-any.whl → 1.3.1.dev8__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.

Potentially problematic release.


This version of modal might be problematic. Click here for more details.

Files changed (139) hide show
  1. modal/__init__.py +4 -4
  2. modal/__main__.py +4 -29
  3. modal/_billing.py +84 -0
  4. modal/_clustered_functions.py +1 -3
  5. modal/_container_entrypoint.py +33 -208
  6. modal/_functions.py +146 -121
  7. modal/_grpc_client.py +191 -0
  8. modal/_ipython.py +16 -6
  9. modal/_load_context.py +106 -0
  10. modal/_object.py +72 -21
  11. modal/_output.py +12 -14
  12. modal/_partial_function.py +31 -4
  13. modal/_resolver.py +44 -57
  14. modal/_runtime/container_io_manager.py +26 -28
  15. modal/_runtime/container_io_manager.pyi +42 -44
  16. modal/_runtime/gpu_memory_snapshot.py +9 -7
  17. modal/_runtime/user_code_event_loop.py +80 -0
  18. modal/_runtime/user_code_imports.py +236 -10
  19. modal/_serialization.py +2 -1
  20. modal/_traceback.py +4 -13
  21. modal/_tunnel.py +16 -11
  22. modal/_tunnel.pyi +25 -3
  23. modal/_utils/async_utils.py +337 -10
  24. modal/_utils/auth_token_manager.py +1 -4
  25. modal/_utils/blob_utils.py +29 -22
  26. modal/_utils/function_utils.py +20 -21
  27. modal/_utils/grpc_testing.py +6 -3
  28. modal/_utils/grpc_utils.py +223 -64
  29. modal/_utils/mount_utils.py +26 -1
  30. modal/_utils/package_utils.py +0 -1
  31. modal/_utils/rand_pb_testing.py +8 -1
  32. modal/_utils/task_command_router_client.py +524 -0
  33. modal/_vendor/cloudpickle.py +144 -48
  34. modal/app.py +215 -96
  35. modal/app.pyi +78 -37
  36. modal/billing.py +5 -0
  37. modal/builder/2025.06.txt +6 -3
  38. modal/builder/PREVIEW.txt +2 -1
  39. modal/builder/base-images.json +4 -2
  40. modal/cli/_download.py +19 -3
  41. modal/cli/cluster.py +4 -2
  42. modal/cli/config.py +3 -1
  43. modal/cli/container.py +5 -4
  44. modal/cli/dict.py +5 -2
  45. modal/cli/entry_point.py +26 -2
  46. modal/cli/environment.py +2 -16
  47. modal/cli/launch.py +1 -76
  48. modal/cli/network_file_system.py +5 -20
  49. modal/cli/queues.py +5 -4
  50. modal/cli/run.py +24 -204
  51. modal/cli/secret.py +1 -2
  52. modal/cli/shell.py +375 -0
  53. modal/cli/utils.py +1 -13
  54. modal/cli/volume.py +11 -17
  55. modal/client.py +16 -125
  56. modal/client.pyi +94 -144
  57. modal/cloud_bucket_mount.py +3 -1
  58. modal/cloud_bucket_mount.pyi +4 -0
  59. modal/cls.py +101 -64
  60. modal/cls.pyi +9 -8
  61. modal/config.py +21 -1
  62. modal/container_process.py +288 -12
  63. modal/container_process.pyi +99 -38
  64. modal/dict.py +72 -33
  65. modal/dict.pyi +88 -57
  66. modal/environments.py +16 -8
  67. modal/environments.pyi +6 -2
  68. modal/exception.py +154 -16
  69. modal/experimental/__init__.py +23 -5
  70. modal/experimental/flash.py +161 -74
  71. modal/experimental/flash.pyi +97 -49
  72. modal/file_io.py +50 -92
  73. modal/file_io.pyi +117 -89
  74. modal/functions.pyi +70 -87
  75. modal/image.py +73 -47
  76. modal/image.pyi +33 -30
  77. modal/io_streams.py +500 -149
  78. modal/io_streams.pyi +279 -189
  79. modal/mount.py +60 -45
  80. modal/mount.pyi +41 -17
  81. modal/network_file_system.py +19 -11
  82. modal/network_file_system.pyi +72 -39
  83. modal/object.pyi +114 -22
  84. modal/parallel_map.py +42 -44
  85. modal/parallel_map.pyi +9 -17
  86. modal/partial_function.pyi +4 -2
  87. modal/proxy.py +14 -6
  88. modal/proxy.pyi +10 -2
  89. modal/queue.py +45 -38
  90. modal/queue.pyi +88 -52
  91. modal/runner.py +96 -96
  92. modal/runner.pyi +44 -27
  93. modal/sandbox.py +225 -108
  94. modal/sandbox.pyi +226 -63
  95. modal/secret.py +58 -56
  96. modal/secret.pyi +28 -13
  97. modal/serving.py +7 -11
  98. modal/serving.pyi +7 -8
  99. modal/snapshot.py +29 -15
  100. modal/snapshot.pyi +18 -10
  101. modal/token_flow.py +1 -1
  102. modal/token_flow.pyi +4 -6
  103. modal/volume.py +102 -55
  104. modal/volume.pyi +125 -66
  105. {modal-1.1.5.dev83.dist-info → modal-1.3.1.dev8.dist-info}/METADATA +10 -9
  106. modal-1.3.1.dev8.dist-info/RECORD +189 -0
  107. modal_proto/api.proto +86 -30
  108. modal_proto/api_grpc.py +10 -25
  109. modal_proto/api_pb2.py +1080 -1047
  110. modal_proto/api_pb2.pyi +253 -79
  111. modal_proto/api_pb2_grpc.py +14 -48
  112. modal_proto/api_pb2_grpc.pyi +6 -18
  113. modal_proto/modal_api_grpc.py +175 -176
  114. modal_proto/{sandbox_router.proto → task_command_router.proto} +62 -45
  115. modal_proto/task_command_router_grpc.py +138 -0
  116. modal_proto/task_command_router_pb2.py +180 -0
  117. modal_proto/{sandbox_router_pb2.pyi → task_command_router_pb2.pyi} +110 -63
  118. modal_proto/task_command_router_pb2_grpc.py +272 -0
  119. modal_proto/task_command_router_pb2_grpc.pyi +100 -0
  120. modal_version/__init__.py +1 -1
  121. modal_version/__main__.py +1 -1
  122. modal/cli/programs/launch_instance_ssh.py +0 -94
  123. modal/cli/programs/run_marimo.py +0 -95
  124. modal-1.1.5.dev83.dist-info/RECORD +0 -191
  125. modal_proto/modal_options_grpc.py +0 -3
  126. modal_proto/options.proto +0 -19
  127. modal_proto/options_grpc.py +0 -3
  128. modal_proto/options_pb2.py +0 -35
  129. modal_proto/options_pb2.pyi +0 -20
  130. modal_proto/options_pb2_grpc.py +0 -4
  131. modal_proto/options_pb2_grpc.pyi +0 -7
  132. modal_proto/sandbox_router_grpc.py +0 -105
  133. modal_proto/sandbox_router_pb2.py +0 -148
  134. modal_proto/sandbox_router_pb2_grpc.py +0 -203
  135. modal_proto/sandbox_router_pb2_grpc.pyi +0 -75
  136. {modal-1.1.5.dev83.dist-info → modal-1.3.1.dev8.dist-info}/WHEEL +0 -0
  137. {modal-1.1.5.dev83.dist-info → modal-1.3.1.dev8.dist-info}/entry_points.txt +0 -0
  138. {modal-1.1.5.dev83.dist-info → modal-1.3.1.dev8.dist-info}/licenses/LICENSE +0 -0
  139. {modal-1.1.5.dev83.dist-info → modal-1.3.1.dev8.dist-info}/top_level.txt +0 -0
modal/parallel_map.pyi CHANGED
@@ -5,6 +5,7 @@ import collections.abc
5
5
  import enum
6
6
  import modal._functions
7
7
  import modal._utils.async_utils
8
+ import modal._utils.grpc_utils
8
9
  import modal.client
9
10
  import modal.functions
10
11
  import modal.retries
@@ -18,31 +19,29 @@ class _SynchronizedQueue:
18
19
  async def put(self, item): ...
19
20
  async def get(self): ...
20
21
 
21
- SUPERSELF = typing.TypeVar("SUPERSELF", covariant=True)
22
-
23
22
  class SynchronizedQueue:
24
23
  """mdmd:hidden"""
25
24
  def __init__(self, /, *args, **kwargs):
26
25
  """Initialize self. See help(type(self)) for accurate signature."""
27
26
  ...
28
27
 
29
- class __init_spec(typing_extensions.Protocol[SUPERSELF]):
28
+ class __init_spec(typing_extensions.Protocol):
30
29
  def __call__(self, /): ...
31
30
  async def aio(self, /): ...
32
31
 
33
- init: __init_spec[typing_extensions.Self]
32
+ init: __init_spec
34
33
 
35
- class __put_spec(typing_extensions.Protocol[SUPERSELF]):
34
+ class __put_spec(typing_extensions.Protocol):
36
35
  def __call__(self, /, item): ...
37
36
  async def aio(self, /, item): ...
38
37
 
39
- put: __put_spec[typing_extensions.Self]
38
+ put: __put_spec
40
39
 
41
- class __get_spec(typing_extensions.Protocol[SUPERSELF]):
40
+ class __get_spec(typing_extensions.Protocol):
42
41
  def __call__(self, /): ...
43
42
  async def aio(self, /): ...
44
43
 
45
- get: __get_spec[typing_extensions.Self]
44
+ get: __get_spec
46
45
 
47
46
  class _OutputValue:
48
47
  """_OutputValue(value: Any)"""
@@ -96,15 +95,8 @@ class InputPumper:
96
95
  ...
97
96
 
98
97
  def pump_inputs(self): ...
99
- async def _send_inputs(
100
- self,
101
- fn: modal.client.UnaryUnaryWrapper,
102
- request: typing.Union[
103
- modal_proto.api_pb2.FunctionPutInputsRequest, modal_proto.api_pb2.FunctionRetryInputsRequest
104
- ],
105
- ) -> typing.Union[
106
- modal_proto.api_pb2.FunctionPutInputsResponse, modal_proto.api_pb2.FunctionRetryInputsResponse
107
- ]: ...
98
+ @property
99
+ def _function_inputs_retry(self) -> modal._utils.grpc_utils.Retry: ...
108
100
 
109
101
  class SyncInputPumper(InputPumper):
110
102
  """Reads inputs from a queue of FunctionPutInputsItems, and sends them to the server."""
@@ -53,7 +53,6 @@ class PartialFunction(
53
53
  ) -> modal.functions.Function[
54
54
  modal._partial_function.P, modal._partial_function.ReturnType, modal._partial_function.OriginalReturnType
55
55
  ]: ...
56
- def __del__(self): ...
57
56
 
58
57
  def method(
59
58
  _warn_parentheses_missing=None, *, is_generator: typing.Optional[bool] = None
@@ -329,7 +328,10 @@ def batched(
329
328
  ...
330
329
 
331
330
  def concurrent(
332
- _warn_parentheses_missing=None, *, max_inputs: int, target_inputs: typing.Optional[int] = None
331
+ _warn_parentheses_missing=None,
332
+ *,
333
+ max_inputs: typing.Optional[int] = None,
334
+ target_inputs: typing.Optional[int] = None,
333
335
  ) -> collections.abc.Callable[
334
336
  [
335
337
  typing.Union[
modal/proxy.py CHANGED
@@ -3,9 +3,11 @@ 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
+ from ._load_context import LoadContext
7
+ from ._object import _Object
7
8
  from ._resolver import Resolver
8
9
  from ._utils.async_utils import synchronize_api
10
+ from .client import _Client
9
11
 
10
12
 
11
13
  class _Proxy(_Object, type_prefix="pr"):
@@ -20,6 +22,7 @@ class _Proxy(_Object, type_prefix="pr"):
20
22
  name: str,
21
23
  *,
22
24
  environment_name: Optional[str] = None,
25
+ client: Optional[_Client] = None,
23
26
  ) -> "_Proxy":
24
27
  """Reference a Proxy by its name.
25
28
 
@@ -28,16 +31,21 @@ class _Proxy(_Object, type_prefix="pr"):
28
31
 
29
32
  """
30
33
 
31
- async def _load(self: _Proxy, resolver: Resolver, existing_object_id: Optional[str]):
34
+ async def _load(self: _Proxy, resolver: Resolver, load_context: LoadContext, existing_object_id: Optional[str]):
32
35
  req = api_pb2.ProxyGetRequest(
33
36
  name=name,
34
- environment_name=_get_environment_name(environment_name, resolver),
37
+ environment_name=load_context.environment_name,
35
38
  )
36
- response: api_pb2.ProxyGetResponse = await resolver.client.stub.ProxyGet(req)
37
- self._hydrate(response.proxy.proxy_id, resolver.client, None)
39
+ response: api_pb2.ProxyGetResponse = await load_context.client.stub.ProxyGet(req)
40
+ self._hydrate(response.proxy.proxy_id, load_context.client, None)
38
41
 
39
42
  rep = _Proxy._repr(name, environment_name)
40
- return _Proxy._from_loader(_load, rep, is_another_app=True)
43
+ return _Proxy._from_loader(
44
+ _load,
45
+ rep,
46
+ is_another_app=True,
47
+ load_context_overrides=LoadContext(client=client, environment_name=environment_name),
48
+ )
41
49
 
42
50
 
43
51
  Proxy = synchronize_api(_Proxy, target_module=__name__)
modal/proxy.pyi CHANGED
@@ -1,4 +1,5 @@
1
1
  import modal._object
2
+ import modal.client
2
3
  import modal.object
3
4
  import typing
4
5
 
@@ -9,7 +10,12 @@ class _Proxy(modal._object._Object):
9
10
  a database. See [the guide](https://modal.com/docs/guide/proxy-ips) for more information.
10
11
  """
11
12
  @staticmethod
12
- def from_name(name: str, *, environment_name: typing.Optional[str] = None) -> _Proxy:
13
+ def from_name(
14
+ name: str,
15
+ *,
16
+ environment_name: typing.Optional[str] = None,
17
+ client: typing.Optional[modal.client._Client] = None,
18
+ ) -> _Proxy:
13
19
  """Reference a Proxy by its name.
14
20
 
15
21
  In contrast to most other Modal objects, new Proxy objects must be
@@ -28,7 +34,9 @@ class Proxy(modal.object.Object):
28
34
  ...
29
35
 
30
36
  @staticmethod
31
- def from_name(name: str, *, environment_name: typing.Optional[str] = None) -> Proxy:
37
+ def from_name(
38
+ name: str, *, environment_name: typing.Optional[str] = None, client: typing.Optional[modal.client.Client] = None
39
+ ) -> Proxy:
32
40
  """Reference a Proxy by its name.
33
41
 
34
42
  In contrast to most other Modal objects, new Proxy objects must be
modal/queue.py CHANGED
@@ -1,4 +1,5 @@
1
1
  # Copyright Modal Labs 2022
2
+ import builtins
2
3
  import queue # The system library
3
4
  import time
4
5
  import warnings
@@ -8,12 +9,13 @@ from datetime import datetime
8
9
  from typing import Any, Optional, Union
9
10
 
10
11
  from google.protobuf.message import Message
11
- from grpclib import GRPCError, Status
12
+ from grpclib import Status
12
13
  from synchronicity import classproperty
13
14
  from synchronicity.async_wrap import asynccontextmanager
14
15
 
15
16
  from modal_proto import api_pb2
16
17
 
18
+ from ._load_context import LoadContext
17
19
  from ._object import (
18
20
  EPHEMERAL_OBJECT_HEARTBEAT_SLEEP,
19
21
  _get_environment_name,
@@ -25,11 +27,11 @@ from ._resolver import Resolver
25
27
  from ._serialization import deserialize, serialize
26
28
  from ._utils.async_utils import TaskContext, synchronize_api, warn_if_generator_is_not_consumed
27
29
  from ._utils.deprecation import deprecation_warning, warn_if_passing_namespace
28
- from ._utils.grpc_utils import retry_transient_errors
30
+ from ._utils.grpc_utils import Retry
29
31
  from ._utils.name_utils import check_object_name
30
32
  from ._utils.time_utils import as_timestamp, timestamp_to_localized_dt
31
33
  from .client import _Client
32
- from .exception import AlreadyExistsError, InvalidError, NotFoundError, RequestSizeError
34
+ from .exception import AlreadyExistsError, Error, InvalidError, NotFoundError, RequestSizeError, ResourceExhaustedError
33
35
 
34
36
 
35
37
  @dataclass
@@ -95,11 +97,9 @@ class _QueueManager:
95
97
  object_creation_type=object_creation_type,
96
98
  )
97
99
  try:
98
- await retry_transient_errors(client.stub.QueueGetOrCreate, req)
99
- except GRPCError as exc:
100
- if exc.status == Status.ALREADY_EXISTS and not allow_existing:
101
- raise AlreadyExistsError(exc.message)
102
- else:
100
+ await client.stub.QueueGetOrCreate(req)
101
+ except AlreadyExistsError:
102
+ if not allow_existing:
103
103
  raise
104
104
 
105
105
  @staticmethod
@@ -109,7 +109,7 @@ class _QueueManager:
109
109
  created_before: Optional[Union[datetime, str]] = None, # Limit based on creation date
110
110
  environment_name: str = "", # Uses active environment if not specified
111
111
  client: Optional[_Client] = None, # Optional client with Modal credentials
112
- ) -> list["_Queue"]:
112
+ ) -> builtins.list["_Queue"]:
113
113
  """Return a list of hydrated Queue objects.
114
114
 
115
115
  **Examples:**
@@ -147,7 +147,7 @@ class _QueueManager:
147
147
  req = api_pb2.QueueListRequest(
148
148
  environment_name=_get_environment_name(environment_name), pagination=pagination
149
149
  )
150
- resp = await retry_transient_errors(client.stub.QueueList, req)
150
+ resp = await client.stub.QueueList(req)
151
151
  items.extend(resp.queues)
152
152
  finished = (len(resp.queues) < max_page_size) or (max_objects is not None and len(items) >= max_objects)
153
153
  return finished
@@ -205,7 +205,7 @@ class _QueueManager:
205
205
  raise
206
206
  else:
207
207
  req = api_pb2.QueueDeleteRequest(queue_id=obj.object_id)
208
- await retry_transient_errors(obj._client.stub.QueueDelete, req)
208
+ await obj._client.stub.QueueDelete(req)
209
209
 
210
210
 
211
211
  QueueManager = synchronize_api(_QueueManager)
@@ -361,6 +361,7 @@ class _Queue(_Object, type_prefix="qu"):
361
361
  namespace=None, # mdmd:line-hidden
362
362
  environment_name: Optional[str] = None,
363
363
  create_if_missing: bool = False,
364
+ client: Optional[_Client] = None,
364
365
  ) -> "_Queue":
365
366
  """Reference a named Queue, creating if necessary.
366
367
 
@@ -376,17 +377,24 @@ class _Queue(_Object, type_prefix="qu"):
376
377
  check_object_name(name, "Queue")
377
378
  warn_if_passing_namespace(namespace, "modal.Queue.from_name")
378
379
 
379
- async def _load(self: _Queue, resolver: Resolver, existing_object_id: Optional[str]):
380
+ async def _load(self: _Queue, resolver: Resolver, load_context: LoadContext, existing_object_id: Optional[str]):
380
381
  req = api_pb2.QueueGetOrCreateRequest(
381
382
  deployment_name=name,
382
- environment_name=_get_environment_name(environment_name, resolver),
383
+ environment_name=load_context.environment_name,
383
384
  object_creation_type=(api_pb2.OBJECT_CREATION_TYPE_CREATE_IF_MISSING if create_if_missing else None),
384
385
  )
385
- response = await resolver.client.stub.QueueGetOrCreate(req)
386
- self._hydrate(response.queue_id, resolver.client, response.metadata)
386
+ response = await load_context.client.stub.QueueGetOrCreate(req)
387
+ self._hydrate(response.queue_id, load_context.client, response.metadata)
387
388
 
388
389
  rep = _Queue._repr(name, environment_name)
389
- return _Queue._from_loader(_load, rep, is_another_app=True, hydrate_lazily=True, name=name)
390
+ return _Queue._from_loader(
391
+ _load,
392
+ rep,
393
+ is_another_app=True,
394
+ hydrate_lazily=True,
395
+ name=name,
396
+ load_context_overrides=LoadContext(environment_name=environment_name, client=client),
397
+ )
390
398
 
391
399
  @staticmethod
392
400
  async def delete(name: str, *, client: Optional[_Client] = None, environment_name: Optional[str] = None):
@@ -424,7 +432,7 @@ class _Queue(_Object, type_prefix="qu"):
424
432
  n_values=n_values,
425
433
  )
426
434
 
427
- response = await retry_transient_errors(self._client.stub.QueueGet, request)
435
+ response = await self._client.stub.QueueGet(request)
428
436
  if response.values:
429
437
  return [deserialize(value, self._client) for value in response.values]
430
438
  else:
@@ -449,7 +457,7 @@ class _Queue(_Object, type_prefix="qu"):
449
457
  n_values=n_values,
450
458
  )
451
459
 
452
- response = await retry_transient_errors(self._client.stub.QueueGet, request)
460
+ response = await self._client.stub.QueueGet(request)
453
461
 
454
462
  if response.values:
455
463
  return [deserialize(value, self._client) for value in response.values]
@@ -469,7 +477,7 @@ class _Queue(_Object, type_prefix="qu"):
469
477
  partition_key=self.validate_partition_key(partition),
470
478
  all_partitions=all,
471
479
  )
472
- await retry_transient_errors(self._client.stub.QueueClear, request)
480
+ await self._client.stub.QueueClear(request)
473
481
 
474
482
  @live_method
475
483
  async def get(
@@ -578,21 +586,22 @@ class _Queue(_Object, type_prefix="qu"):
578
586
  partition_ttl_seconds=partition_ttl,
579
587
  )
580
588
  try:
581
- await retry_transient_errors(
582
- self._client.stub.QueuePut,
589
+ await self._client.stub.QueuePut(
583
590
  request,
584
591
  # A full queue will return this status.
585
- additional_status_codes=[Status.RESOURCE_EXHAUSTED],
586
- max_delay=30.0,
587
- max_retries=None,
588
- total_timeout=timeout,
592
+ retry=Retry(
593
+ additional_status_codes=[Status.RESOURCE_EXHAUSTED],
594
+ max_delay=30.0,
595
+ max_retries=None,
596
+ total_timeout=timeout,
597
+ ),
589
598
  )
590
- except GRPCError as exc:
591
- if exc.status == Status.RESOURCE_EXHAUSTED:
592
- raise queue.Full(str(exc))
593
- elif "status = '413'" in exc.message:
599
+ except Error as exc:
600
+ if "status = '413'" in str(exc):
594
601
  method = "put_many" if len(vs) > 1 else "put"
595
602
  raise RequestSizeError(f"Queue.{method} request is too large") from exc
603
+ elif isinstance(exc, ResourceExhaustedError):
604
+ raise queue.Full(str(exc))
596
605
  else:
597
606
  raise exc
598
607
 
@@ -605,13 +614,13 @@ class _Queue(_Object, type_prefix="qu"):
605
614
  partition_ttl_seconds=partition_ttl,
606
615
  )
607
616
  try:
608
- await retry_transient_errors(self._client.stub.QueuePut, request)
609
- except GRPCError as exc:
610
- if exc.status == Status.RESOURCE_EXHAUSTED:
611
- raise queue.Full(exc.message)
612
- elif "status = '413'" in exc.message:
617
+ await self._client.stub.QueuePut(request)
618
+ except Error as exc:
619
+ if "status = '413'" in str(exc):
613
620
  method = "put_many" if len(vs) > 1 else "put"
614
621
  raise RequestSizeError(f"Queue.{method} request is too large") from exc
622
+ elif isinstance(exc, ResourceExhaustedError):
623
+ raise queue.Full(str(exc))
615
624
  else:
616
625
  raise exc
617
626
 
@@ -625,7 +634,7 @@ class _Queue(_Object, type_prefix="qu"):
625
634
  partition_key=self.validate_partition_key(partition),
626
635
  total=total,
627
636
  )
628
- response = await retry_transient_errors(self._client.stub.QueueLen, request)
637
+ response = await self._client.stub.QueueLen(request)
629
638
  return response.len
630
639
 
631
640
  @warn_if_generator_is_not_consumed()
@@ -651,9 +660,7 @@ class _Queue(_Object, type_prefix="qu"):
651
660
  item_poll_timeout=poll_duration,
652
661
  )
653
662
 
654
- response: api_pb2.QueueNextItemsResponse = await retry_transient_errors(
655
- self._client.stub.QueueNextItems, request
656
- )
663
+ response: api_pb2.QueueNextItemsResponse = await self._client.stub.QueueNextItems(request)
657
664
  if response.items:
658
665
  for item in response.items:
659
666
  yield deserialize(item.value, self._client)
modal/queue.pyi CHANGED
@@ -213,7 +213,7 @@ class QueueManager:
213
213
  """
214
214
  ...
215
215
 
216
- create: __create_spec
216
+ create: typing.ClassVar[__create_spec]
217
217
 
218
218
  class __list_spec(typing_extensions.Protocol):
219
219
  def __call__(
@@ -286,7 +286,7 @@ class QueueManager:
286
286
  """
287
287
  ...
288
288
 
289
- list: __list_spec
289
+ list: typing.ClassVar[__list_spec]
290
290
 
291
291
  class __delete_spec(typing_extensions.Protocol):
292
292
  def __call__(
@@ -349,7 +349,7 @@ class QueueManager:
349
349
  """
350
350
  ...
351
351
 
352
- delete: __delete_spec
352
+ delete: typing.ClassVar[__delete_spec]
353
353
 
354
354
  class _Queue(modal._object._Object):
355
355
  """Distributed, FIFO queue for data flow in Modal apps.
@@ -464,7 +464,12 @@ class _Queue(modal._object._Object):
464
464
 
465
465
  @staticmethod
466
466
  def from_name(
467
- name: str, *, namespace=None, environment_name: typing.Optional[str] = None, create_if_missing: bool = False
467
+ name: str,
468
+ *,
469
+ namespace=None,
470
+ environment_name: typing.Optional[str] = None,
471
+ create_if_missing: bool = False,
472
+ client: typing.Optional[modal.client._Client] = None,
468
473
  ) -> _Queue:
469
474
  """Reference a named Queue, creating if necessary.
470
475
 
@@ -606,8 +611,6 @@ class _Queue(modal._object._Object):
606
611
  """
607
612
  ...
608
613
 
609
- SUPERSELF = typing.TypeVar("SUPERSELF", covariant=True)
610
-
611
614
  class Queue(modal.object.Object):
612
615
  """Distributed, FIFO queue for data flow in Modal apps.
613
616
 
@@ -695,33 +698,66 @@ class Queue(modal.object.Object):
695
698
  def _get_metadata(self) -> modal_proto.api_pb2.QueueMetadata: ...
696
699
  @staticmethod
697
700
  def validate_partition_key(partition: typing.Optional[str]) -> bytes: ...
698
- @classmethod
699
- def ephemeral(
700
- cls: type[Queue],
701
- client: typing.Optional[modal.client.Client] = None,
702
- environment_name: typing.Optional[str] = None,
703
- _heartbeat_sleep: float = 300,
704
- ) -> synchronicity.combined_types.AsyncAndBlockingContextManager[Queue]:
705
- """Creates a new ephemeral queue within a context manager:
706
701
 
707
- Usage:
708
- ```python
709
- from modal import Queue
702
+ class __ephemeral_spec(typing_extensions.Protocol):
703
+ def __call__(
704
+ self,
705
+ /,
706
+ client: typing.Optional[modal.client.Client] = None,
707
+ environment_name: typing.Optional[str] = None,
708
+ _heartbeat_sleep: float = 300,
709
+ ) -> synchronicity.combined_types.AsyncAndBlockingContextManager[Queue]:
710
+ """Creates a new ephemeral queue within a context manager:
710
711
 
711
- with Queue.ephemeral() as q:
712
- q.put(123)
713
- ```
712
+ Usage:
713
+ ```python
714
+ from modal import Queue
714
715
 
715
- ```python notest
716
- async with Queue.ephemeral() as q:
717
- await q.put.aio(123)
718
- ```
719
- """
720
- ...
716
+ with Queue.ephemeral() as q:
717
+ q.put(123)
718
+ ```
719
+
720
+ ```python notest
721
+ async with Queue.ephemeral() as q:
722
+ await q.put.aio(123)
723
+ ```
724
+ """
725
+ ...
726
+
727
+ def aio(
728
+ self,
729
+ /,
730
+ client: typing.Optional[modal.client.Client] = None,
731
+ environment_name: typing.Optional[str] = None,
732
+ _heartbeat_sleep: float = 300,
733
+ ) -> typing.AsyncContextManager[Queue]:
734
+ """Creates a new ephemeral queue within a context manager:
735
+
736
+ Usage:
737
+ ```python
738
+ from modal import Queue
739
+
740
+ with Queue.ephemeral() as q:
741
+ q.put(123)
742
+ ```
743
+
744
+ ```python notest
745
+ async with Queue.ephemeral() as q:
746
+ await q.put.aio(123)
747
+ ```
748
+ """
749
+ ...
750
+
751
+ ephemeral: typing.ClassVar[__ephemeral_spec]
721
752
 
722
753
  @staticmethod
723
754
  def from_name(
724
- name: str, *, namespace=None, environment_name: typing.Optional[str] = None, create_if_missing: bool = False
755
+ name: str,
756
+ *,
757
+ namespace=None,
758
+ environment_name: typing.Optional[str] = None,
759
+ create_if_missing: bool = False,
760
+ client: typing.Optional[modal.client.Client] = None,
725
761
  ) -> Queue:
726
762
  """Reference a named Queue, creating if necessary.
727
763
 
@@ -773,9 +809,9 @@ class Queue(modal.object.Object):
773
809
  """
774
810
  ...
775
811
 
776
- delete: __delete_spec
812
+ delete: typing.ClassVar[__delete_spec]
777
813
 
778
- class __info_spec(typing_extensions.Protocol[SUPERSELF]):
814
+ class __info_spec(typing_extensions.Protocol):
779
815
  def __call__(self, /) -> QueueInfo:
780
816
  """Return information about the Queue object."""
781
817
  ...
@@ -784,15 +820,15 @@ class Queue(modal.object.Object):
784
820
  """Return information about the Queue object."""
785
821
  ...
786
822
 
787
- info: __info_spec[typing_extensions.Self]
823
+ info: __info_spec
788
824
 
789
- class ___get_nonblocking_spec(typing_extensions.Protocol[SUPERSELF]):
825
+ class ___get_nonblocking_spec(typing_extensions.Protocol):
790
826
  def __call__(self, /, partition: typing.Optional[str], n_values: int) -> list[typing.Any]: ...
791
827
  async def aio(self, /, partition: typing.Optional[str], n_values: int) -> list[typing.Any]: ...
792
828
 
793
- _get_nonblocking: ___get_nonblocking_spec[typing_extensions.Self]
829
+ _get_nonblocking: ___get_nonblocking_spec
794
830
 
795
- class ___get_blocking_spec(typing_extensions.Protocol[SUPERSELF]):
831
+ class ___get_blocking_spec(typing_extensions.Protocol):
796
832
  def __call__(
797
833
  self, /, partition: typing.Optional[str], timeout: typing.Optional[float], n_values: int
798
834
  ) -> list[typing.Any]: ...
@@ -800,9 +836,9 @@ class Queue(modal.object.Object):
800
836
  self, /, partition: typing.Optional[str], timeout: typing.Optional[float], n_values: int
801
837
  ) -> list[typing.Any]: ...
802
838
 
803
- _get_blocking: ___get_blocking_spec[typing_extensions.Self]
839
+ _get_blocking: ___get_blocking_spec
804
840
 
805
- class __clear_spec(typing_extensions.Protocol[SUPERSELF]):
841
+ class __clear_spec(typing_extensions.Protocol):
806
842
  def __call__(self, /, *, partition: typing.Optional[str] = None, all: bool = False) -> None:
807
843
  """Clear the contents of a single partition or all partitions."""
808
844
  ...
@@ -811,9 +847,9 @@ class Queue(modal.object.Object):
811
847
  """Clear the contents of a single partition or all partitions."""
812
848
  ...
813
849
 
814
- clear: __clear_spec[typing_extensions.Self]
850
+ clear: __clear_spec
815
851
 
816
- class __get_spec(typing_extensions.Protocol[SUPERSELF]):
852
+ class __get_spec(typing_extensions.Protocol):
817
853
  def __call__(
818
854
  self,
819
855
  /,
@@ -852,9 +888,9 @@ class Queue(modal.object.Object):
852
888
  """
853
889
  ...
854
890
 
855
- get: __get_spec[typing_extensions.Self]
891
+ get: __get_spec
856
892
 
857
- class __get_many_spec(typing_extensions.Protocol[SUPERSELF]):
893
+ class __get_many_spec(typing_extensions.Protocol):
858
894
  def __call__(
859
895
  self,
860
896
  /,
@@ -899,9 +935,9 @@ class Queue(modal.object.Object):
899
935
  """
900
936
  ...
901
937
 
902
- get_many: __get_many_spec[typing_extensions.Self]
938
+ get_many: __get_many_spec
903
939
 
904
- class __put_spec(typing_extensions.Protocol[SUPERSELF]):
940
+ class __put_spec(typing_extensions.Protocol):
905
941
  def __call__(
906
942
  self,
907
943
  /,
@@ -944,9 +980,9 @@ class Queue(modal.object.Object):
944
980
  """
945
981
  ...
946
982
 
947
- put: __put_spec[typing_extensions.Self]
983
+ put: __put_spec
948
984
 
949
- class __put_many_spec(typing_extensions.Protocol[SUPERSELF]):
985
+ class __put_many_spec(typing_extensions.Protocol):
950
986
  def __call__(
951
987
  self,
952
988
  /,
@@ -989,9 +1025,9 @@ class Queue(modal.object.Object):
989
1025
  """
990
1026
  ...
991
1027
 
992
- put_many: __put_many_spec[typing_extensions.Self]
1028
+ put_many: __put_many_spec
993
1029
 
994
- class ___put_many_blocking_spec(typing_extensions.Protocol[SUPERSELF]):
1030
+ class ___put_many_blocking_spec(typing_extensions.Protocol):
995
1031
  def __call__(
996
1032
  self,
997
1033
  /,
@@ -1009,15 +1045,15 @@ class Queue(modal.object.Object):
1009
1045
  timeout: typing.Optional[float] = None,
1010
1046
  ): ...
1011
1047
 
1012
- _put_many_blocking: ___put_many_blocking_spec[typing_extensions.Self]
1048
+ _put_many_blocking: ___put_many_blocking_spec
1013
1049
 
1014
- class ___put_many_nonblocking_spec(typing_extensions.Protocol[SUPERSELF]):
1050
+ class ___put_many_nonblocking_spec(typing_extensions.Protocol):
1015
1051
  def __call__(self, /, partition: typing.Optional[str], partition_ttl: int, vs: list[typing.Any]): ...
1016
1052
  async def aio(self, /, partition: typing.Optional[str], partition_ttl: int, vs: list[typing.Any]): ...
1017
1053
 
1018
- _put_many_nonblocking: ___put_many_nonblocking_spec[typing_extensions.Self]
1054
+ _put_many_nonblocking: ___put_many_nonblocking_spec
1019
1055
 
1020
- class __len_spec(typing_extensions.Protocol[SUPERSELF]):
1056
+ class __len_spec(typing_extensions.Protocol):
1021
1057
  def __call__(self, /, *, partition: typing.Optional[str] = None, total: bool = False) -> int:
1022
1058
  """Return the number of objects in the queue partition."""
1023
1059
  ...
@@ -1026,9 +1062,9 @@ class Queue(modal.object.Object):
1026
1062
  """Return the number of objects in the queue partition."""
1027
1063
  ...
1028
1064
 
1029
- len: __len_spec[typing_extensions.Self]
1065
+ len: __len_spec
1030
1066
 
1031
- class __iterate_spec(typing_extensions.Protocol[SUPERSELF]):
1067
+ class __iterate_spec(typing_extensions.Protocol):
1032
1068
  def __call__(
1033
1069
  self, /, *, partition: typing.Optional[str] = None, item_poll_timeout: float = 0.0
1034
1070
  ) -> typing.Generator[typing.Any, None, None]:
@@ -1047,4 +1083,4 @@ class Queue(modal.object.Object):
1047
1083
  """
1048
1084
  ...
1049
1085
 
1050
- iterate: __iterate_spec[typing_extensions.Self]
1086
+ iterate: __iterate_spec