modal 1.1.2.dev44__tar.gz → 1.1.3__tar.gz
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-1.1.2.dev44 → modal-1.1.3}/PKG-INFO +1 -1
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/_functions.py +116 -26
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/app.py +2 -2
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/client.pyi +2 -10
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/dict.py +7 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/dict.pyi +18 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/functions.pyi +49 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/image.py +2 -1
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/image.pyi +4 -2
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/parallel_map.py +21 -2
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/parallel_map.pyi +3 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/queue.py +7 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/queue.pyi +18 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/secret.py +7 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/secret.pyi +18 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/volume.py +10 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/volume.pyi +21 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal.egg-info/PKG-INFO +1 -1
- {modal-1.1.2.dev44 → modal-1.1.3}/modal_proto/api.proto +8 -3
- {modal-1.1.2.dev44 → modal-1.1.3}/modal_proto/api_pb2.py +493 -493
- {modal-1.1.2.dev44 → modal-1.1.3}/modal_proto/api_pb2.pyi +15 -6
- {modal-1.1.2.dev44 → modal-1.1.3}/modal_version/__init__.py +1 -1
- {modal-1.1.2.dev44 → modal-1.1.3}/LICENSE +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/README.md +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/__init__.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/__main__.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/_clustered_functions.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/_clustered_functions.pyi +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/_container_entrypoint.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/_ipython.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/_location.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/_object.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/_output.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/_partial_function.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/_pty.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/_resolver.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/_resources.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/_runtime/__init__.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/_runtime/asgi.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/_runtime/container_io_manager.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/_runtime/container_io_manager.pyi +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/_runtime/execution_context.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/_runtime/execution_context.pyi +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/_runtime/gpu_memory_snapshot.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/_runtime/telemetry.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/_runtime/user_code_imports.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/_serialization.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/_traceback.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/_tunnel.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/_tunnel.pyi +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/_type_manager.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/_utils/__init__.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/_utils/app_utils.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/_utils/async_utils.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/_utils/auth_token_manager.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/_utils/blob_utils.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/_utils/bytes_io_segment_payload.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/_utils/deprecation.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/_utils/docker_utils.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/_utils/function_utils.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/_utils/git_utils.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/_utils/grpc_testing.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/_utils/grpc_utils.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/_utils/hash_utils.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/_utils/http_utils.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/_utils/jwt_utils.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/_utils/logger.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/_utils/mount_utils.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/_utils/name_utils.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/_utils/package_utils.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/_utils/pattern_utils.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/_utils/rand_pb_testing.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/_utils/shell_utils.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/_utils/time_utils.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/_vendor/__init__.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/_vendor/a2wsgi_wsgi.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/_vendor/cloudpickle.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/_vendor/tblib.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/_watcher.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/app.pyi +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/builder/2023.12.312.txt +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/builder/2023.12.txt +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/builder/2024.04.txt +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/builder/2024.10.txt +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/builder/2025.06.txt +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/builder/PREVIEW.txt +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/builder/README.md +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/builder/base-images.json +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/call_graph.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/cli/__init__.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/cli/_download.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/cli/_traceback.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/cli/app.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/cli/cluster.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/cli/config.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/cli/container.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/cli/dict.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/cli/entry_point.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/cli/environment.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/cli/import_refs.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/cli/launch.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/cli/network_file_system.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/cli/profile.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/cli/programs/__init__.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/cli/programs/launch_instance_ssh.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/cli/programs/run_jupyter.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/cli/programs/run_marimo.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/cli/programs/vscode.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/cli/queues.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/cli/run.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/cli/secret.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/cli/token.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/cli/utils.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/cli/volume.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/client.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/cloud_bucket_mount.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/cloud_bucket_mount.pyi +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/cls.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/cls.pyi +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/config.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/container_process.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/container_process.pyi +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/environments.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/environments.pyi +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/exception.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/experimental/__init__.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/experimental/flash.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/experimental/flash.pyi +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/experimental/ipython.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/file_io.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/file_io.pyi +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/file_pattern_matcher.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/functions.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/gpu.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/io_streams.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/io_streams.pyi +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/mount.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/mount.pyi +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/network_file_system.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/network_file_system.pyi +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/object.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/object.pyi +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/output.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/partial_function.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/partial_function.pyi +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/proxy.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/proxy.pyi +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/py.typed +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/retries.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/runner.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/runner.pyi +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/running_app.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/sandbox.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/sandbox.pyi +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/schedule.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/scheduler_placement.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/serving.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/serving.pyi +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/snapshot.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/snapshot.pyi +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/stream_type.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/token_flow.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal/token_flow.pyi +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal.egg-info/SOURCES.txt +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal.egg-info/dependency_links.txt +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal.egg-info/entry_points.txt +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal.egg-info/requires.txt +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal.egg-info/top_level.txt +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal_docs/__init__.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal_docs/gen_cli_docs.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal_docs/gen_reference_docs.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal_docs/mdmd/__init__.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal_docs/mdmd/mdmd.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal_docs/mdmd/signatures.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal_proto/__init__.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal_proto/api_grpc.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal_proto/api_pb2_grpc.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal_proto/api_pb2_grpc.pyi +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal_proto/modal_api_grpc.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal_proto/modal_options_grpc.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal_proto/options.proto +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal_proto/options_grpc.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal_proto/options_pb2.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal_proto/options_pb2.pyi +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal_proto/options_pb2_grpc.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal_proto/options_pb2_grpc.pyi +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal_proto/py.typed +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/modal_version/__main__.py +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/pyproject.toml +0 -0
- {modal-1.1.2.dev44 → modal-1.1.3}/setup.cfg +0 -0
@@ -9,7 +9,7 @@ import warnings
|
|
9
9
|
from collections.abc import AsyncGenerator, Sequence, Sized
|
10
10
|
from dataclasses import dataclass
|
11
11
|
from pathlib import PurePosixPath
|
12
|
-
from typing import TYPE_CHECKING, Any, Callable, Optional, Union
|
12
|
+
from typing import TYPE_CHECKING, Any, AsyncIterator, Callable, Optional, Union
|
13
13
|
|
14
14
|
import typing_extensions
|
15
15
|
from google.protobuf.message import Message
|
@@ -100,6 +100,10 @@ if TYPE_CHECKING:
|
|
100
100
|
import modal.partial_function
|
101
101
|
|
102
102
|
MAX_INTERNAL_FAILURE_COUNT = 8
|
103
|
+
TERMINAL_STATUSES = (
|
104
|
+
api_pb2.GenericResult.GENERIC_STATUS_SUCCESS,
|
105
|
+
api_pb2.GenericResult.GENERIC_STATUS_TERMINATED,
|
106
|
+
)
|
103
107
|
|
104
108
|
|
105
109
|
@dataclasses.dataclass
|
@@ -300,11 +304,7 @@ class _Invocation:
|
|
300
304
|
|
301
305
|
while True:
|
302
306
|
item = await self._get_single_output(ctx.input_jwt)
|
303
|
-
if item.result.status in
|
304
|
-
api_pb2.GenericResult.GENERIC_STATUS_SUCCESS,
|
305
|
-
api_pb2.GenericResult.GENERIC_STATUS_TERMINATED,
|
306
|
-
):
|
307
|
-
# success or cancellations are "final" results
|
307
|
+
if item.result.status in TERMINAL_STATUSES:
|
308
308
|
return await _process_result(item.result, item.data_format, self.stub, self.client)
|
309
309
|
|
310
310
|
if item.result.status != api_pb2.GenericResult.GENERIC_STATUS_INTERNAL_FAILURE:
|
@@ -360,6 +360,43 @@ class _Invocation:
|
|
360
360
|
if items_total is not None and items_received >= items_total:
|
361
361
|
break
|
362
362
|
|
363
|
+
async def enumerate(self, start_index: int, end_index: int):
|
364
|
+
"""Iterate over the results of the function call in the range [start_index, end_index)."""
|
365
|
+
limit = 49
|
366
|
+
current_index = start_index
|
367
|
+
while current_index < end_index:
|
368
|
+
# batch_end_indx is inclusive, so we subtract 1 to get the last index in the batch.
|
369
|
+
batch_end_index = min(current_index + limit, end_index) - 1
|
370
|
+
request = api_pb2.FunctionGetOutputsRequest(
|
371
|
+
function_call_id=self.function_call_id,
|
372
|
+
timeout=0,
|
373
|
+
last_entry_id="0-0",
|
374
|
+
clear_on_success=False,
|
375
|
+
requested_at=time.time(),
|
376
|
+
start_idx=current_index,
|
377
|
+
end_idx=batch_end_index,
|
378
|
+
)
|
379
|
+
response: api_pb2.FunctionGetOutputsResponse = await retry_transient_errors(
|
380
|
+
self.stub.FunctionGetOutputs,
|
381
|
+
request,
|
382
|
+
attempt_timeout=ATTEMPT_TIMEOUT_GRACE_PERIOD,
|
383
|
+
)
|
384
|
+
|
385
|
+
outputs = list(response.outputs)
|
386
|
+
outputs.sort(key=lambda x: x.idx)
|
387
|
+
for output in outputs:
|
388
|
+
if output.idx != current_index:
|
389
|
+
break
|
390
|
+
result = await _process_result(output.result, output.data_format, self.stub, self.client)
|
391
|
+
yield output.idx, result
|
392
|
+
current_index += 1
|
393
|
+
|
394
|
+
# We're missing current_index, so we need to poll the function for the next result
|
395
|
+
if len(outputs) < (batch_end_index - current_index + 1):
|
396
|
+
result = await self.poll_function(index=current_index)
|
397
|
+
yield current_index, result
|
398
|
+
current_index += 1
|
399
|
+
|
363
400
|
|
364
401
|
class _InputPlaneInvocation:
|
365
402
|
"""Internal client representation of a single-input call to a Modal Function using the input
|
@@ -374,6 +411,7 @@ class _InputPlaneInvocation:
|
|
374
411
|
client: _Client,
|
375
412
|
input_item: api_pb2.FunctionPutInputsItem,
|
376
413
|
function_id: str,
|
414
|
+
retry_policy: api_pb2.FunctionRetryPolicy,
|
377
415
|
input_plane_region: str,
|
378
416
|
):
|
379
417
|
self.stub = stub
|
@@ -381,6 +419,7 @@ class _InputPlaneInvocation:
|
|
381
419
|
self.attempt_token = attempt_token
|
382
420
|
self.input_item = input_item
|
383
421
|
self.function_id = function_id
|
422
|
+
self.retry_policy = retry_policy
|
384
423
|
self.input_plane_region = input_plane_region
|
385
424
|
|
386
425
|
@staticmethod
|
@@ -416,11 +455,15 @@ class _InputPlaneInvocation:
|
|
416
455
|
response = await retry_transient_errors(stub.AttemptStart, request, metadata=metadata)
|
417
456
|
attempt_token = response.attempt_token
|
418
457
|
|
419
|
-
return _InputPlaneInvocation(
|
458
|
+
return _InputPlaneInvocation(
|
459
|
+
stub, attempt_token, client, input_item, function_id, response.retry_policy, input_plane_region
|
460
|
+
)
|
420
461
|
|
421
462
|
async def run_function(self) -> Any:
|
463
|
+
# User errors including timeouts are managed by the user-specified retry policy.
|
464
|
+
user_retry_manager = RetryManager(self.retry_policy)
|
465
|
+
|
422
466
|
# This will retry when the server returns GENERIC_STATUS_INTERNAL_FAILURE, i.e. lost inputs or worker preemption
|
423
|
-
# TODO(ryan): add logic to retry for user defined retry policy
|
424
467
|
internal_failure_count = 0
|
425
468
|
while True:
|
426
469
|
await_request = api_pb2.AttemptAwaitRequest(
|
@@ -437,32 +480,48 @@ class _InputPlaneInvocation:
|
|
437
480
|
)
|
438
481
|
|
439
482
|
if await_response.HasField("output"):
|
483
|
+
if await_response.output.result.status in TERMINAL_STATUSES:
|
484
|
+
return await _process_result(
|
485
|
+
await_response.output.result, await_response.output.data_format, self.client.stub, self.client
|
486
|
+
)
|
487
|
+
|
440
488
|
if await_response.output.result.status == api_pb2.GenericResult.GENERIC_STATUS_INTERNAL_FAILURE:
|
441
489
|
internal_failure_count += 1
|
442
490
|
# Limit the number of times we retry
|
443
491
|
if internal_failure_count < MAX_INTERNAL_FAILURE_COUNT:
|
444
492
|
# For system failures on the server, we retry immediately,
|
445
493
|
# and the failure does not count towards the retry policy.
|
446
|
-
|
447
|
-
function_id=self.function_id,
|
448
|
-
parent_input_id=current_input_id() or "",
|
449
|
-
input=self.input_item,
|
450
|
-
attempt_token=self.attempt_token,
|
451
|
-
)
|
452
|
-
# TODO(ryan): Add exponential backoff?
|
453
|
-
retry_response = await retry_transient_errors(
|
454
|
-
self.stub.AttemptRetry,
|
455
|
-
retry_request,
|
456
|
-
metadata=metadata,
|
457
|
-
)
|
458
|
-
self.attempt_token = retry_response.attempt_token
|
494
|
+
self.attempt_token = await self._retry_input(metadata)
|
459
495
|
continue
|
460
496
|
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
497
|
+
# We add delays between retries for non-internal failures.
|
498
|
+
delay_ms = user_retry_manager.get_delay_ms()
|
499
|
+
if delay_ms is None:
|
500
|
+
# No more retries either because we reached the retry limit or user didn't set a retry policy
|
501
|
+
# and the limit defaulted to 0.
|
502
|
+
# An unsuccessful status should raise an error when it's converted to an exception.
|
503
|
+
# Note: Blob download is done on the control plane stub not the input plane stub!
|
504
|
+
return await _process_result(
|
505
|
+
await_response.output.result, await_response.output.data_format, self.client.stub, self.client
|
506
|
+
)
|
507
|
+
await asyncio.sleep(delay_ms / 1000)
|
508
|
+
|
509
|
+
await self._retry_input(metadata)
|
510
|
+
|
511
|
+
async def _retry_input(self, metadata: list[tuple[str, str]]) -> str:
|
512
|
+
retry_request = api_pb2.AttemptRetryRequest(
|
513
|
+
function_id=self.function_id,
|
514
|
+
parent_input_id=current_input_id() or "",
|
515
|
+
input=self.input_item,
|
516
|
+
attempt_token=self.attempt_token,
|
517
|
+
)
|
518
|
+
# TODO(ryan): Add exponential backoff?
|
519
|
+
retry_response = await retry_transient_errors(
|
520
|
+
self.stub.AttemptRetry,
|
521
|
+
retry_request,
|
522
|
+
metadata=metadata,
|
523
|
+
)
|
524
|
+
return retry_response.attempt_token
|
466
525
|
|
467
526
|
async def run_generator(self):
|
468
527
|
items_received = 0
|
@@ -1865,6 +1924,36 @@ class _FunctionCall(typing.Generic[ReturnType], _Object, type_prefix="fc"):
|
|
1865
1924
|
"""
|
1866
1925
|
return await self._invocation().poll_function(timeout=timeout, index=index)
|
1867
1926
|
|
1927
|
+
@live_method_gen
|
1928
|
+
async def iter(self, *, start: int = 0, end: Optional[int] = None) -> AsyncIterator[ReturnType]:
|
1929
|
+
"""Iterate in-order over the results of the function call.
|
1930
|
+
|
1931
|
+
Optionally, specify a range [start, end) to iterate over.
|
1932
|
+
|
1933
|
+
Example:
|
1934
|
+
```python
|
1935
|
+
@app.function()
|
1936
|
+
def my_func(a):
|
1937
|
+
return a ** 2
|
1938
|
+
|
1939
|
+
|
1940
|
+
@app.local_entrypoint()
|
1941
|
+
def main():
|
1942
|
+
fc = my_func.spawn_map([1, 2, 3, 4])
|
1943
|
+
assert list(fc.iter()) == [1, 4, 9, 16]
|
1944
|
+
assert list(fc.iter(start=1, end=3)) == [4, 9]
|
1945
|
+
```
|
1946
|
+
|
1947
|
+
If `end` is not provided, it will iterate over all results.
|
1948
|
+
"""
|
1949
|
+
num_inputs = await self.num_inputs()
|
1950
|
+
if end is None:
|
1951
|
+
end = num_inputs
|
1952
|
+
if start < 0 or end > num_inputs:
|
1953
|
+
raise ValueError(f"Invalid index range: {start} to {end} for {num_inputs} inputs")
|
1954
|
+
async for _, item in self._invocation().enumerate(start_index=start, end_index=end):
|
1955
|
+
yield item
|
1956
|
+
|
1868
1957
|
async def get_call_graph(self) -> list[InputInfo]:
|
1869
1958
|
"""Returns a structure representing the call graph from a given root
|
1870
1959
|
call ID, along with the status of execution for each node.
|
@@ -1926,6 +2015,7 @@ class _FunctionCall(typing.Generic[ReturnType], _Object, type_prefix="fc"):
|
|
1926
2015
|
fc: _FunctionCall[Any] = _FunctionCall._from_loader(_load, rep, hydrate_lazily=True)
|
1927
2016
|
# We already know the object ID, so we can set it directly
|
1928
2017
|
fc._object_id = function_call_id
|
2018
|
+
fc._client = client
|
1929
2019
|
return fc
|
1930
2020
|
|
1931
2021
|
@staticmethod
|
@@ -641,7 +641,7 @@ class _App:
|
|
641
641
|
scaledown_window: Optional[int] = None, # Max time (in seconds) a container can remain idle while scaling down.
|
642
642
|
proxy: Optional[_Proxy] = None, # Reference to a Modal Proxy to use in front of this function.
|
643
643
|
retries: Optional[Union[int, Retries]] = None, # Number of times to retry each input in case of failure.
|
644
|
-
timeout: int = 300, # Maximum execution time
|
644
|
+
timeout: int = 300, # Maximum execution time in seconds.
|
645
645
|
name: Optional[str] = None, # Sets the Modal name of the function within the app
|
646
646
|
is_generator: Optional[
|
647
647
|
bool
|
@@ -869,7 +869,7 @@ class _App:
|
|
869
869
|
scaledown_window: Optional[int] = None, # Max time (in seconds) a container can remain idle while scaling down.
|
870
870
|
proxy: Optional[_Proxy] = None, # Reference to a Modal Proxy to use in front of this function.
|
871
871
|
retries: Optional[Union[int, Retries]] = None, # Number of times to retry each input in case of failure.
|
872
|
-
timeout: int = 300, # Maximum execution time
|
872
|
+
timeout: int = 300, # Maximum execution time in seconds; applies independently to startup and each input.
|
873
873
|
cloud: Optional[str] = None, # Cloud provider to run the function on. Possible values are aws, gcp, oci, auto.
|
874
874
|
region: Optional[Union[str, Sequence[str]]] = None, # Region or regions to run the function on.
|
875
875
|
enable_memory_snapshot: bool = False, # Enable memory checkpointing for faster cold starts.
|
@@ -29,11 +29,7 @@ class _Client:
|
|
29
29
|
_snapshotted: bool
|
30
30
|
|
31
31
|
def __init__(
|
32
|
-
self,
|
33
|
-
server_url: str,
|
34
|
-
client_type: int,
|
35
|
-
credentials: typing.Optional[tuple[str, str]],
|
36
|
-
version: str = "1.1.2.dev44",
|
32
|
+
self, server_url: str, client_type: int, credentials: typing.Optional[tuple[str, str]], version: str = "1.1.3"
|
37
33
|
):
|
38
34
|
"""mdmd:hidden
|
39
35
|
The Modal client object is not intended to be instantiated directly by users.
|
@@ -160,11 +156,7 @@ class Client:
|
|
160
156
|
_snapshotted: bool
|
161
157
|
|
162
158
|
def __init__(
|
163
|
-
self,
|
164
|
-
server_url: str,
|
165
|
-
client_type: int,
|
166
|
-
credentials: typing.Optional[tuple[str, str]],
|
167
|
-
version: str = "1.1.2.dev44",
|
159
|
+
self, server_url: str, client_type: int, credentials: typing.Optional[tuple[str, str]], version: str = "1.1.3"
|
168
160
|
):
|
169
161
|
"""mdmd:hidden
|
170
162
|
The Modal client object is not intended to be instantiated directly by users.
|
@@ -81,6 +81,8 @@ class _DictManager:
|
|
81
81
|
Note that this method does not return a local instance of the Dict. You can use
|
82
82
|
`modal.Dict.from_name` to perform a lookup after creation.
|
83
83
|
|
84
|
+
Added in v1.1.2.
|
85
|
+
|
84
86
|
"""
|
85
87
|
check_object_name(name, "Dict")
|
86
88
|
client = await _Client.from_env() if client is None else client
|
@@ -132,6 +134,8 @@ class _DictManager:
|
|
132
134
|
dicts = modal.Dict.objects.list(max_objects=10, created_before="2025-01-01")
|
133
135
|
```
|
134
136
|
|
137
|
+
Added in v1.1.2.
|
138
|
+
|
135
139
|
"""
|
136
140
|
client = await _Client.from_env() if client is None else client
|
137
141
|
if max_objects is not None and max_objects < 0:
|
@@ -192,6 +196,9 @@ class _DictManager:
|
|
192
196
|
```python notest
|
193
197
|
await modal.Dict.objects.delete("my-dict", environment_name="dev")
|
194
198
|
```
|
199
|
+
|
200
|
+
Added in v1.1.2.
|
201
|
+
|
195
202
|
"""
|
196
203
|
try:
|
197
204
|
obj = await _Dict.from_name(name, environment_name=environment_name).hydrate(client)
|
@@ -66,6 +66,8 @@ class _DictManager:
|
|
66
66
|
|
67
67
|
Note that this method does not return a local instance of the Dict. You can use
|
68
68
|
`modal.Dict.from_name` to perform a lookup after creation.
|
69
|
+
|
70
|
+
Added in v1.1.2.
|
69
71
|
"""
|
70
72
|
...
|
71
73
|
|
@@ -98,6 +100,8 @@ class _DictManager:
|
|
98
100
|
```python
|
99
101
|
dicts = modal.Dict.objects.list(max_objects=10, created_before="2025-01-01")
|
100
102
|
```
|
103
|
+
|
104
|
+
Added in v1.1.2.
|
101
105
|
"""
|
102
106
|
...
|
103
107
|
|
@@ -125,6 +129,8 @@ class _DictManager:
|
|
125
129
|
```python notest
|
126
130
|
await modal.Dict.objects.delete("my-dict", environment_name="dev")
|
127
131
|
```
|
132
|
+
|
133
|
+
Added in v1.1.2.
|
128
134
|
"""
|
129
135
|
...
|
130
136
|
|
@@ -167,6 +173,8 @@ class DictManager:
|
|
167
173
|
|
168
174
|
Note that this method does not return a local instance of the Dict. You can use
|
169
175
|
`modal.Dict.from_name` to perform a lookup after creation.
|
176
|
+
|
177
|
+
Added in v1.1.2.
|
170
178
|
"""
|
171
179
|
...
|
172
180
|
|
@@ -202,6 +210,8 @@ class DictManager:
|
|
202
210
|
|
203
211
|
Note that this method does not return a local instance of the Dict. You can use
|
204
212
|
`modal.Dict.from_name` to perform a lookup after creation.
|
213
|
+
|
214
|
+
Added in v1.1.2.
|
205
215
|
"""
|
206
216
|
...
|
207
217
|
|
@@ -238,6 +248,8 @@ class DictManager:
|
|
238
248
|
```python
|
239
249
|
dicts = modal.Dict.objects.list(max_objects=10, created_before="2025-01-01")
|
240
250
|
```
|
251
|
+
|
252
|
+
Added in v1.1.2.
|
241
253
|
"""
|
242
254
|
...
|
243
255
|
|
@@ -271,6 +283,8 @@ class DictManager:
|
|
271
283
|
```python
|
272
284
|
dicts = modal.Dict.objects.list(max_objects=10, created_before="2025-01-01")
|
273
285
|
```
|
286
|
+
|
287
|
+
Added in v1.1.2.
|
274
288
|
"""
|
275
289
|
...
|
276
290
|
|
@@ -302,6 +316,8 @@ class DictManager:
|
|
302
316
|
```python notest
|
303
317
|
await modal.Dict.objects.delete("my-dict", environment_name="dev")
|
304
318
|
```
|
319
|
+
|
320
|
+
Added in v1.1.2.
|
305
321
|
"""
|
306
322
|
...
|
307
323
|
|
@@ -330,6 +346,8 @@ class DictManager:
|
|
330
346
|
```python notest
|
331
347
|
await modal.Dict.objects.delete("my-dict", environment_name="dev")
|
332
348
|
```
|
349
|
+
|
350
|
+
Added in v1.1.2.
|
333
351
|
"""
|
334
352
|
...
|
335
353
|
|
@@ -788,6 +788,55 @@ class FunctionCall(typing.Generic[modal._functions.ReturnType], modal.object.Obj
|
|
788
788
|
|
789
789
|
get: __get_spec[modal._functions.ReturnType, typing_extensions.Self]
|
790
790
|
|
791
|
+
class __iter_spec(typing_extensions.Protocol[ReturnType_INNER, SUPERSELF]):
|
792
|
+
def __call__(self, /, *, start: int = 0, end: typing.Optional[int] = None) -> typing.Iterator[ReturnType_INNER]:
|
793
|
+
"""Iterate in-order over the results of the function call.
|
794
|
+
|
795
|
+
Optionally, specify a range [start, end) to iterate over.
|
796
|
+
|
797
|
+
Example:
|
798
|
+
```python
|
799
|
+
@app.function()
|
800
|
+
def my_func(a):
|
801
|
+
return a ** 2
|
802
|
+
|
803
|
+
|
804
|
+
@app.local_entrypoint()
|
805
|
+
def main():
|
806
|
+
fc = my_func.spawn_map([1, 2, 3, 4])
|
807
|
+
assert list(fc.iter()) == [1, 4, 9, 16]
|
808
|
+
assert list(fc.iter(start=1, end=3)) == [4, 9]
|
809
|
+
```
|
810
|
+
|
811
|
+
If `end` is not provided, it will iterate over all results.
|
812
|
+
"""
|
813
|
+
...
|
814
|
+
|
815
|
+
def aio(self, /, *, start: int = 0, end: typing.Optional[int] = None) -> typing.AsyncIterator[ReturnType_INNER]:
|
816
|
+
"""Iterate in-order over the results of the function call.
|
817
|
+
|
818
|
+
Optionally, specify a range [start, end) to iterate over.
|
819
|
+
|
820
|
+
Example:
|
821
|
+
```python
|
822
|
+
@app.function()
|
823
|
+
def my_func(a):
|
824
|
+
return a ** 2
|
825
|
+
|
826
|
+
|
827
|
+
@app.local_entrypoint()
|
828
|
+
def main():
|
829
|
+
fc = my_func.spawn_map([1, 2, 3, 4])
|
830
|
+
assert list(fc.iter()) == [1, 4, 9, 16]
|
831
|
+
assert list(fc.iter(start=1, end=3)) == [4, 9]
|
832
|
+
```
|
833
|
+
|
834
|
+
If `end` is not provided, it will iterate over all results.
|
835
|
+
"""
|
836
|
+
...
|
837
|
+
|
838
|
+
iter: __iter_spec[modal._functions.ReturnType, typing_extensions.Self]
|
839
|
+
|
791
840
|
class __get_call_graph_spec(typing_extensions.Protocol[SUPERSELF]):
|
792
841
|
def __call__(self, /) -> list[modal.call_graph.InputInfo]:
|
793
842
|
"""Returns a structure representing the call graph from a given root
|
@@ -1356,7 +1356,8 @@ class _Image(_Object, type_prefix="im"):
|
|
1356
1356
|
image = modal.Image.debian_slim().uv_sync()
|
1357
1357
|
```
|
1358
1358
|
|
1359
|
-
The `pyproject.toml` and `uv.lock` in `uv_project_dir` are automatically added to the build context.
|
1359
|
+
The `pyproject.toml` and `uv.lock` in `uv_project_dir` are automatically added to the build context. The
|
1360
|
+
`uv_project_dir` is relative to the current working directory of where `modal` is called.
|
1360
1361
|
|
1361
1362
|
Added in v1.1.0.
|
1362
1363
|
"""
|
@@ -524,7 +524,8 @@ class _Image(modal._object._Object):
|
|
524
524
|
image = modal.Image.debian_slim().uv_sync()
|
525
525
|
```
|
526
526
|
|
527
|
-
The `pyproject.toml` and `uv.lock` in `uv_project_dir` are automatically added to the build context.
|
527
|
+
The `pyproject.toml` and `uv.lock` in `uv_project_dir` are automatically added to the build context. The
|
528
|
+
`uv_project_dir` is relative to the current working directory of where `modal` is called.
|
528
529
|
|
529
530
|
Added in v1.1.0.
|
530
531
|
"""
|
@@ -1368,7 +1369,8 @@ class Image(modal.object.Object):
|
|
1368
1369
|
image = modal.Image.debian_slim().uv_sync()
|
1369
1370
|
```
|
1370
1371
|
|
1371
|
-
The `pyproject.toml` and `uv.lock` in `uv_project_dir` are automatically added to the build context.
|
1372
|
+
The `pyproject.toml` and `uv.lock` in `uv_project_dir` are automatically added to the build context. The
|
1373
|
+
`uv_project_dir` is relative to the current working directory of where `modal` is called.
|
1372
1374
|
|
1373
1375
|
Added in v1.1.0.
|
1374
1376
|
"""
|
@@ -673,9 +673,11 @@ async def _map_invocation_inputplane(
|
|
673
673
|
# any reason).
|
674
674
|
max_inputs_outstanding = MAX_INPUTS_OUTSTANDING_DEFAULT
|
675
675
|
|
676
|
-
#
|
676
|
+
# Set a default retry policy to construct an instance of _MapItemsManager.
|
677
|
+
# We'll update the retry policy with the actual user-specified retry policy
|
678
|
+
# from the server in the first MapStartOrContinue response.
|
677
679
|
retry_policy = api_pb2.FunctionRetryPolicy(
|
678
|
-
retries=0,
|
680
|
+
retries=0,
|
679
681
|
initial_delay_ms=1000,
|
680
682
|
max_delay_ms=1000,
|
681
683
|
backoff_coefficient=1.0,
|
@@ -771,10 +773,17 @@ async def _map_invocation_inputplane(
|
|
771
773
|
|
772
774
|
map_items_manager.handle_put_continue_response(response_items_idx_tuple)
|
773
775
|
|
776
|
+
# Set the function call id and actual retry policy with the data from the first response.
|
777
|
+
# This conditional is skipped for subsequent iterations of this for-loop.
|
774
778
|
if function_call_id is None:
|
775
779
|
function_call_id = response.function_call_id
|
776
780
|
function_call_id_received.set()
|
777
781
|
max_inputs_outstanding = response.max_inputs_outstanding or MAX_INPUTS_OUTSTANDING_DEFAULT
|
782
|
+
map_items_manager.set_retry_policy(response.retry_policy)
|
783
|
+
# Update the retry policy for the first batch of inputs.
|
784
|
+
# Subsequent batches will have the correct user-specified retry policy
|
785
|
+
# set by the updated _MapItemsManager.
|
786
|
+
map_items_manager.update_items_retry_policy(response.retry_policy)
|
778
787
|
yield
|
779
788
|
|
780
789
|
async def check_lost_inputs():
|
@@ -1475,6 +1484,9 @@ class _MapItemContext:
|
|
1475
1484
|
retry_count=self.retry_manager.retry_count,
|
1476
1485
|
)
|
1477
1486
|
|
1487
|
+
def set_retry_policy(self, retry_policy: api_pb2.FunctionRetryPolicy):
|
1488
|
+
self.retry_manager = RetryManager(retry_policy)
|
1489
|
+
|
1478
1490
|
def handle_retry_response(self, input_jwt: str):
|
1479
1491
|
self.input_jwt.set_result(input_jwt)
|
1480
1492
|
self.state = _MapItemState.WAITING_FOR_OUTPUT
|
@@ -1511,6 +1523,9 @@ class _MapItemsManager:
|
|
1511
1523
|
self._sync_client_retries_enabled = sync_client_retries_enabled
|
1512
1524
|
self._is_input_plane_instance = is_input_plane_instance
|
1513
1525
|
|
1526
|
+
def set_retry_policy(self, retry_policy: api_pb2.FunctionRetryPolicy):
|
1527
|
+
self._retry_policy = retry_policy
|
1528
|
+
|
1514
1529
|
async def add_items(self, items: list[api_pb2.FunctionPutInputsItem]):
|
1515
1530
|
for item in items:
|
1516
1531
|
# acquire semaphore to limit the number of inputs in progress
|
@@ -1540,6 +1555,10 @@ class _MapItemsManager:
|
|
1540
1555
|
async def prepare_items_for_retry(self, retriable_idxs: list[int]) -> list[api_pb2.FunctionRetryInputsItem]:
|
1541
1556
|
return [await self._item_context[idx].prepare_item_for_retry() for idx in retriable_idxs]
|
1542
1557
|
|
1558
|
+
def update_items_retry_policy(self, retry_policy: api_pb2.FunctionRetryPolicy):
|
1559
|
+
for ctx in self._item_context.values():
|
1560
|
+
ctx.set_retry_policy(retry_policy)
|
1561
|
+
|
1543
1562
|
def get_input_jwts_waiting_for_output(self) -> list[str]:
|
1544
1563
|
"""
|
1545
1564
|
Returns a list of input_jwts for inputs that are waiting for output.
|
@@ -406,6 +406,7 @@ class _MapItemContext:
|
|
406
406
|
...
|
407
407
|
|
408
408
|
async def prepare_item_for_retry(self) -> modal_proto.api_pb2.FunctionRetryInputsItem: ...
|
409
|
+
def set_retry_policy(self, retry_policy: modal_proto.api_pb2.FunctionRetryPolicy): ...
|
409
410
|
def handle_retry_response(self, input_jwt: str): ...
|
410
411
|
async def create_map_start_or_continue_item(self, idx: int) -> modal_proto.api_pb2.MapStartOrContinueItem: ...
|
411
412
|
|
@@ -422,11 +423,13 @@ class _MapItemsManager:
|
|
422
423
|
"""Initialize self. See help(type(self)) for accurate signature."""
|
423
424
|
...
|
424
425
|
|
426
|
+
def set_retry_policy(self, retry_policy: modal_proto.api_pb2.FunctionRetryPolicy): ...
|
425
427
|
async def add_items(self, items: list[modal_proto.api_pb2.FunctionPutInputsItem]): ...
|
426
428
|
async def add_items_inputplane(self, items: list[modal_proto.api_pb2.MapStartOrContinueItem]): ...
|
427
429
|
async def prepare_items_for_retry(
|
428
430
|
self, retriable_idxs: list[int]
|
429
431
|
) -> list[modal_proto.api_pb2.FunctionRetryInputsItem]: ...
|
432
|
+
def update_items_retry_policy(self, retry_policy: modal_proto.api_pb2.FunctionRetryPolicy): ...
|
430
433
|
def get_input_jwts_waiting_for_output(self) -> list[str]:
|
431
434
|
"""Returns a list of input_jwts for inputs that are waiting for output."""
|
432
435
|
...
|
@@ -79,6 +79,8 @@ class _QueueManager:
|
|
79
79
|
Note that this method does not return a local instance of the Queue. You can use
|
80
80
|
`modal.Queue.from_name` to perform a lookup after creation.
|
81
81
|
|
82
|
+
Added in v1.1.2.
|
83
|
+
|
82
84
|
"""
|
83
85
|
check_object_name(name, "Queue")
|
84
86
|
client = await _Client.from_env() if client is None else client
|
@@ -130,6 +132,8 @@ class _QueueManager:
|
|
130
132
|
queues = modal.Queue.objects.list(max_objects=10, created_before="2025-01-01")
|
131
133
|
```
|
132
134
|
|
135
|
+
Added in v1.1.2.
|
136
|
+
|
133
137
|
"""
|
134
138
|
client = await _Client.from_env() if client is None else client
|
135
139
|
if max_objects is not None and max_objects < 0:
|
@@ -190,6 +194,9 @@ class _QueueManager:
|
|
190
194
|
```python notest
|
191
195
|
await modal.Queue.objects.delete("my-queue", environment_name="dev")
|
192
196
|
```
|
197
|
+
|
198
|
+
Added in v1.1.2.
|
199
|
+
|
193
200
|
"""
|
194
201
|
try:
|
195
202
|
obj = await _Queue.from_name(name, environment_name=environment_name).hydrate(client)
|
@@ -64,6 +64,8 @@ class _QueueManager:
|
|
64
64
|
|
65
65
|
Note that this method does not return a local instance of the Queue. You can use
|
66
66
|
`modal.Queue.from_name` to perform a lookup after creation.
|
67
|
+
|
68
|
+
Added in v1.1.2.
|
67
69
|
"""
|
68
70
|
...
|
69
71
|
|
@@ -96,6 +98,8 @@ class _QueueManager:
|
|
96
98
|
```python
|
97
99
|
queues = modal.Queue.objects.list(max_objects=10, created_before="2025-01-01")
|
98
100
|
```
|
101
|
+
|
102
|
+
Added in v1.1.2.
|
99
103
|
"""
|
100
104
|
...
|
101
105
|
|
@@ -123,6 +127,8 @@ class _QueueManager:
|
|
123
127
|
```python notest
|
124
128
|
await modal.Queue.objects.delete("my-queue", environment_name="dev")
|
125
129
|
```
|
130
|
+
|
131
|
+
Added in v1.1.2.
|
126
132
|
"""
|
127
133
|
...
|
128
134
|
|
@@ -165,6 +171,8 @@ class QueueManager:
|
|
165
171
|
|
166
172
|
Note that this method does not return a local instance of the Queue. You can use
|
167
173
|
`modal.Queue.from_name` to perform a lookup after creation.
|
174
|
+
|
175
|
+
Added in v1.1.2.
|
168
176
|
"""
|
169
177
|
...
|
170
178
|
|
@@ -200,6 +208,8 @@ class QueueManager:
|
|
200
208
|
|
201
209
|
Note that this method does not return a local instance of the Queue. You can use
|
202
210
|
`modal.Queue.from_name` to perform a lookup after creation.
|
211
|
+
|
212
|
+
Added in v1.1.2.
|
203
213
|
"""
|
204
214
|
...
|
205
215
|
|
@@ -236,6 +246,8 @@ class QueueManager:
|
|
236
246
|
```python
|
237
247
|
queues = modal.Queue.objects.list(max_objects=10, created_before="2025-01-01")
|
238
248
|
```
|
249
|
+
|
250
|
+
Added in v1.1.2.
|
239
251
|
"""
|
240
252
|
...
|
241
253
|
|
@@ -269,6 +281,8 @@ class QueueManager:
|
|
269
281
|
```python
|
270
282
|
queues = modal.Queue.objects.list(max_objects=10, created_before="2025-01-01")
|
271
283
|
```
|
284
|
+
|
285
|
+
Added in v1.1.2.
|
272
286
|
"""
|
273
287
|
...
|
274
288
|
|
@@ -300,6 +314,8 @@ class QueueManager:
|
|
300
314
|
```python notest
|
301
315
|
await modal.Queue.objects.delete("my-queue", environment_name="dev")
|
302
316
|
```
|
317
|
+
|
318
|
+
Added in v1.1.2.
|
303
319
|
"""
|
304
320
|
...
|
305
321
|
|
@@ -328,6 +344,8 @@ class QueueManager:
|
|
328
344
|
```python notest
|
329
345
|
await modal.Queue.objects.delete("my-queue", environment_name="dev")
|
330
346
|
```
|
347
|
+
|
348
|
+
Added in v1.1.2.
|
331
349
|
"""
|
332
350
|
...
|
333
351
|
|