modal 1.2.5.dev4__tar.gz → 1.2.5.dev6__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.2.5.dev4 → modal-1.2.5.dev6}/PKG-INFO +1 -1
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_utils/grpc_utils.py +3 -1
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_utils/task_command_router_client.py +8 -6
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/client.pyi +2 -2
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/functions.pyi +6 -6
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/io_streams.py +71 -93
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/io_streams.pyi +28 -26
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal.egg-info/PKG-INFO +1 -1
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal_version/__init__.py +1 -1
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/LICENSE +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/README.md +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/__init__.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/__main__.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_billing.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_clustered_functions.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_clustered_functions.pyi +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_container_entrypoint.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_functions.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_grpc_client.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_ipython.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_load_context.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_location.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_object.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_output.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_partial_function.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_pty.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_resolver.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_resources.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_runtime/__init__.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_runtime/asgi.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_runtime/container_io_manager.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_runtime/container_io_manager.pyi +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_runtime/execution_context.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_runtime/execution_context.pyi +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_runtime/gpu_memory_snapshot.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_runtime/telemetry.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_runtime/user_code_event_loop.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_runtime/user_code_imports.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_serialization.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_traceback.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_tunnel.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_tunnel.pyi +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_type_manager.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_utils/__init__.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_utils/app_utils.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_utils/async_utils.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_utils/auth_token_manager.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_utils/blob_utils.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_utils/bytes_io_segment_payload.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_utils/deprecation.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_utils/docker_utils.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_utils/function_utils.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_utils/git_utils.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_utils/grpc_testing.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_utils/hash_utils.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_utils/http_utils.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_utils/jwt_utils.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_utils/logger.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_utils/mount_utils.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_utils/name_utils.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_utils/package_utils.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_utils/pattern_utils.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_utils/rand_pb_testing.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_utils/shell_utils.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_utils/time_utils.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_vendor/__init__.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_vendor/a2wsgi_wsgi.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_vendor/cloudpickle.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_vendor/tblib.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/_watcher.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/app.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/app.pyi +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/billing.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/builder/2023.12.312.txt +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/builder/2023.12.txt +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/builder/2024.04.txt +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/builder/2024.10.txt +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/builder/2025.06.txt +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/builder/PREVIEW.txt +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/builder/README.md +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/builder/base-images.json +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/call_graph.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/cli/__init__.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/cli/_download.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/cli/_traceback.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/cli/app.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/cli/cluster.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/cli/config.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/cli/container.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/cli/dict.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/cli/entry_point.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/cli/environment.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/cli/import_refs.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/cli/launch.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/cli/network_file_system.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/cli/profile.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/cli/programs/__init__.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/cli/programs/launch_instance_ssh.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/cli/programs/run_jupyter.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/cli/programs/run_marimo.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/cli/programs/vscode.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/cli/queues.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/cli/run.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/cli/secret.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/cli/shell.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/cli/token.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/cli/utils.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/cli/volume.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/client.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/cloud_bucket_mount.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/cloud_bucket_mount.pyi +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/cls.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/cls.pyi +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/config.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/container_process.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/container_process.pyi +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/dict.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/dict.pyi +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/environments.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/environments.pyi +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/exception.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/experimental/__init__.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/experimental/flash.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/experimental/flash.pyi +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/experimental/ipython.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/file_io.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/file_io.pyi +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/file_pattern_matcher.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/functions.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/gpu.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/image.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/image.pyi +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/mount.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/mount.pyi +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/network_file_system.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/network_file_system.pyi +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/object.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/object.pyi +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/output.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/parallel_map.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/parallel_map.pyi +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/partial_function.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/partial_function.pyi +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/proxy.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/proxy.pyi +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/py.typed +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/queue.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/queue.pyi +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/retries.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/runner.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/runner.pyi +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/running_app.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/sandbox.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/sandbox.pyi +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/schedule.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/scheduler_placement.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/secret.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/secret.pyi +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/serving.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/serving.pyi +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/snapshot.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/snapshot.pyi +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/stream_type.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/token_flow.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/token_flow.pyi +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/volume.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal/volume.pyi +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal.egg-info/SOURCES.txt +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal.egg-info/dependency_links.txt +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal.egg-info/entry_points.txt +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal.egg-info/requires.txt +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal.egg-info/top_level.txt +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal_docs/__init__.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal_docs/gen_cli_docs.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal_docs/gen_reference_docs.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal_docs/mdmd/__init__.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal_docs/mdmd/mdmd.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal_docs/mdmd/signatures.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal_proto/__init__.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal_proto/api.proto +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal_proto/api_grpc.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal_proto/api_pb2.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal_proto/api_pb2.pyi +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal_proto/api_pb2_grpc.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal_proto/api_pb2_grpc.pyi +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal_proto/modal_api_grpc.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal_proto/py.typed +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal_proto/sandbox_router.proto +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal_proto/sandbox_router_grpc.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal_proto/sandbox_router_pb2.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal_proto/sandbox_router_pb2.pyi +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal_proto/sandbox_router_pb2_grpc.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal_proto/sandbox_router_pb2_grpc.pyi +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal_proto/task_command_router.proto +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal_proto/task_command_router_grpc.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal_proto/task_command_router_pb2.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal_proto/task_command_router_pb2.pyi +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal_proto/task_command_router_pb2_grpc.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal_proto/task_command_router_pb2_grpc.pyi +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/modal_version/__main__.py +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/pyproject.toml +0 -0
- {modal-1.2.5.dev4 → modal-1.2.5.dev6}/setup.cfg +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# Copyright Modal Labs 2022
|
|
2
2
|
import asyncio
|
|
3
3
|
import contextlib
|
|
4
|
+
import os
|
|
4
5
|
import platform
|
|
5
6
|
import socket
|
|
6
7
|
import time
|
|
@@ -396,7 +397,8 @@ async def _retry_transient_errors(
|
|
|
396
397
|
):
|
|
397
398
|
last_server_retry_warning_time = now
|
|
398
399
|
logger.warning(
|
|
399
|
-
f"Warning: Received {exc.status}
|
|
400
|
+
f"Warning: Received {exc.status}{os.linesep}"
|
|
401
|
+
f"{exc.message}{os.linesep}"
|
|
400
402
|
f"Will retry in {server_delay:0.2f} seconds."
|
|
401
403
|
)
|
|
402
404
|
|
|
@@ -5,7 +5,7 @@ import json
|
|
|
5
5
|
import ssl
|
|
6
6
|
import time
|
|
7
7
|
import urllib.parse
|
|
8
|
-
from typing import
|
|
8
|
+
from typing import AsyncGenerator, Optional
|
|
9
9
|
|
|
10
10
|
import grpclib.client
|
|
11
11
|
import grpclib.config
|
|
@@ -18,6 +18,7 @@ from modal.exception import ExecTimeoutError
|
|
|
18
18
|
from modal_proto import api_pb2, task_command_router_pb2 as sr_pb2
|
|
19
19
|
from modal_proto.task_command_router_grpc import TaskCommandRouterStub
|
|
20
20
|
|
|
21
|
+
from .async_utils import aclosing
|
|
21
22
|
from .grpc_utils import RETRYABLE_GRPC_STATUS_CODES, connect_channel
|
|
22
23
|
|
|
23
24
|
|
|
@@ -242,7 +243,7 @@ class TaskCommandRouterClient:
|
|
|
242
243
|
# Quotes around the type required for protobuf 3.19.
|
|
243
244
|
file_descriptor: "api_pb2.FileDescriptor.ValueType",
|
|
244
245
|
deadline: Optional[float] = None,
|
|
245
|
-
) ->
|
|
246
|
+
) -> AsyncGenerator[sr_pb2.TaskExecStdioReadResponse, None]:
|
|
246
247
|
"""Stream stdout/stderr batches from the task, properly retrying on transient errors.
|
|
247
248
|
|
|
248
249
|
Args:
|
|
@@ -253,7 +254,7 @@ class TaskCommandRouterClient:
|
|
|
253
254
|
None, wait forever. If the deadline is exceeded, raises an
|
|
254
255
|
ExecTimeoutError.
|
|
255
256
|
Returns:
|
|
256
|
-
|
|
257
|
+
AsyncGenerator[sr_pb2.TaskExecStdioReadResponse, None]: A stream of stdout/stderr batches.
|
|
257
258
|
Raises:
|
|
258
259
|
ExecTimeoutError: If the deadline is exceeded.
|
|
259
260
|
Other errors: If retries are exhausted on transient errors or if there's an error
|
|
@@ -268,8 +269,9 @@ class TaskCommandRouterClient:
|
|
|
268
269
|
else:
|
|
269
270
|
raise ValueError(f"Invalid file descriptor: {file_descriptor}")
|
|
270
271
|
|
|
271
|
-
async
|
|
272
|
-
|
|
272
|
+
async with aclosing(self._stream_stdio(task_id, exec_id, sr_fd, deadline)) as stream:
|
|
273
|
+
async for item in stream:
|
|
274
|
+
yield item
|
|
273
275
|
|
|
274
276
|
async def exec_stdin_write(
|
|
275
277
|
self, task_id: str, exec_id: str, offset: int, data: bytes, eof: bool
|
|
@@ -453,7 +455,7 @@ class TaskCommandRouterClient:
|
|
|
453
455
|
# Quotes around the type required for protobuf 3.19.
|
|
454
456
|
file_descriptor: "sr_pb2.TaskExecStdioFileDescriptor.ValueType",
|
|
455
457
|
deadline: Optional[float] = None,
|
|
456
|
-
) ->
|
|
458
|
+
) -> AsyncGenerator[sr_pb2.TaskExecStdioReadResponse, None]:
|
|
457
459
|
"""Stream stdio from the task, properly updating the offset and retrying on transient errors.
|
|
458
460
|
Raises ExecTimeoutError if the deadline is exceeded.
|
|
459
461
|
"""
|
|
@@ -32,7 +32,7 @@ class _Client:
|
|
|
32
32
|
server_url: str,
|
|
33
33
|
client_type: int,
|
|
34
34
|
credentials: typing.Optional[tuple[str, str]],
|
|
35
|
-
version: str = "1.2.5.
|
|
35
|
+
version: str = "1.2.5.dev6",
|
|
36
36
|
):
|
|
37
37
|
"""mdmd:hidden
|
|
38
38
|
The Modal client object is not intended to be instantiated directly by users.
|
|
@@ -163,7 +163,7 @@ class Client:
|
|
|
163
163
|
server_url: str,
|
|
164
164
|
client_type: int,
|
|
165
165
|
credentials: typing.Optional[tuple[str, str]],
|
|
166
|
-
version: str = "1.2.5.
|
|
166
|
+
version: str = "1.2.5.dev6",
|
|
167
167
|
):
|
|
168
168
|
"""mdmd:hidden
|
|
169
169
|
The Modal client object is not intended to be instantiated directly by users.
|
|
@@ -408,7 +408,7 @@ class Function(
|
|
|
408
408
|
|
|
409
409
|
_call_generator: ___call_generator_spec[typing_extensions.Self]
|
|
410
410
|
|
|
411
|
-
class __remote_spec(typing_extensions.Protocol[
|
|
411
|
+
class __remote_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER, SUPERSELF]):
|
|
412
412
|
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> ReturnType_INNER:
|
|
413
413
|
"""Calls the function remotely, executing it with the given arguments and returning the execution's result."""
|
|
414
414
|
...
|
|
@@ -417,7 +417,7 @@ class Function(
|
|
|
417
417
|
"""Calls the function remotely, executing it with the given arguments and returning the execution's result."""
|
|
418
418
|
...
|
|
419
419
|
|
|
420
|
-
remote: __remote_spec[modal._functions.
|
|
420
|
+
remote: __remote_spec[modal._functions.P, modal._functions.ReturnType, typing_extensions.Self]
|
|
421
421
|
|
|
422
422
|
class __remote_gen_spec(typing_extensions.Protocol[SUPERSELF]):
|
|
423
423
|
def __call__(self, /, *args, **kwargs) -> typing.Generator[typing.Any, None, None]:
|
|
@@ -444,7 +444,7 @@ class Function(
|
|
|
444
444
|
"""
|
|
445
445
|
...
|
|
446
446
|
|
|
447
|
-
class ___experimental_spawn_spec(typing_extensions.Protocol[
|
|
447
|
+
class ___experimental_spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER, SUPERSELF]):
|
|
448
448
|
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
|
|
449
449
|
"""[Experimental] Calls the function with the given arguments, without waiting for the results.
|
|
450
450
|
|
|
@@ -468,7 +468,7 @@ class Function(
|
|
|
468
468
|
...
|
|
469
469
|
|
|
470
470
|
_experimental_spawn: ___experimental_spawn_spec[
|
|
471
|
-
modal._functions.
|
|
471
|
+
modal._functions.P, modal._functions.ReturnType, typing_extensions.Self
|
|
472
472
|
]
|
|
473
473
|
|
|
474
474
|
class ___spawn_map_inner_spec(typing_extensions.Protocol[P_INNER, SUPERSELF]):
|
|
@@ -477,7 +477,7 @@ class Function(
|
|
|
477
477
|
|
|
478
478
|
_spawn_map_inner: ___spawn_map_inner_spec[modal._functions.P, typing_extensions.Self]
|
|
479
479
|
|
|
480
|
-
class __spawn_spec(typing_extensions.Protocol[
|
|
480
|
+
class __spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER, SUPERSELF]):
|
|
481
481
|
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
|
|
482
482
|
"""Calls the function with the given arguments, without waiting for the results.
|
|
483
483
|
|
|
@@ -498,7 +498,7 @@ class Function(
|
|
|
498
498
|
"""
|
|
499
499
|
...
|
|
500
500
|
|
|
501
|
-
spawn: __spawn_spec[modal._functions.
|
|
501
|
+
spawn: __spawn_spec[modal._functions.P, modal._functions.ReturnType, typing_extensions.Self]
|
|
502
502
|
|
|
503
503
|
def get_raw_f(self) -> collections.abc.Callable[..., typing.Any]:
|
|
504
504
|
"""Return the inner Python object wrapped by this Modal Function."""
|
|
@@ -11,6 +11,7 @@ from typing import (
|
|
|
11
11
|
Generic,
|
|
12
12
|
Literal,
|
|
13
13
|
Optional,
|
|
14
|
+
TextIO,
|
|
14
15
|
TypeVar,
|
|
15
16
|
Union,
|
|
16
17
|
cast,
|
|
@@ -22,7 +23,7 @@ from grpclib.exceptions import GRPCError, StreamTerminatedError
|
|
|
22
23
|
from modal.exception import ClientClosed, ExecTimeoutError, InvalidError
|
|
23
24
|
from modal_proto import api_pb2
|
|
24
25
|
|
|
25
|
-
from ._utils.async_utils import synchronize_api
|
|
26
|
+
from ._utils.async_utils import aclosing, synchronize_api
|
|
26
27
|
from ._utils.grpc_utils import RETRYABLE_GRPC_STATUS_CODES
|
|
27
28
|
from ._utils.task_command_router_client import TaskCommandRouterClient
|
|
28
29
|
from .client import _Client
|
|
@@ -292,7 +293,7 @@ class _StreamReaderThroughServer(Generic[T]):
|
|
|
292
293
|
yield self._line_buffer
|
|
293
294
|
self._line_buffer = b""
|
|
294
295
|
|
|
295
|
-
def
|
|
296
|
+
def __aiter__(self) -> AsyncGenerator[T, None]:
|
|
296
297
|
if not self._stream:
|
|
297
298
|
if self._by_line:
|
|
298
299
|
# TODO: This is quite odd - it does line buffering in binary mode
|
|
@@ -306,11 +307,6 @@ class _StreamReaderThroughServer(Generic[T]):
|
|
|
306
307
|
self._stream = cast(AsyncGenerator[T, None], stream)
|
|
307
308
|
return self._stream
|
|
308
309
|
|
|
309
|
-
async def __anext__(self) -> T:
|
|
310
|
-
"""mdmd:hidden"""
|
|
311
|
-
stream = self._ensure_stream()
|
|
312
|
-
return cast(T, await stream.__anext__())
|
|
313
|
-
|
|
314
310
|
async def aclose(self):
|
|
315
311
|
"""mdmd:hidden"""
|
|
316
312
|
if self._stream:
|
|
@@ -336,17 +332,23 @@ async def _decode_bytes_stream_to_str(stream: AsyncGenerator[bytes, None]) -> As
|
|
|
336
332
|
|
|
337
333
|
|
|
338
334
|
async def _stream_by_line(stream: AsyncGenerator[bytes, None]) -> AsyncGenerator[bytes, None]:
|
|
339
|
-
"""Yield complete lines only (ending with \n), buffering partial lines until complete.
|
|
335
|
+
"""Yield complete lines only (ending with \n), buffering partial lines until complete.
|
|
336
|
+
|
|
337
|
+
When this generator returns, the underlying generator is closed.
|
|
338
|
+
"""
|
|
340
339
|
line_buffer = b""
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
340
|
+
try:
|
|
341
|
+
async for message in stream:
|
|
342
|
+
assert isinstance(message, bytes)
|
|
343
|
+
line_buffer += message
|
|
344
|
+
while b"\n" in line_buffer:
|
|
345
|
+
line, line_buffer = line_buffer.split(b"\n", 1)
|
|
346
|
+
yield line + b"\n"
|
|
347
347
|
|
|
348
|
-
|
|
349
|
-
|
|
348
|
+
if line_buffer:
|
|
349
|
+
yield line_buffer
|
|
350
|
+
finally:
|
|
351
|
+
await stream.aclose()
|
|
350
352
|
|
|
351
353
|
|
|
352
354
|
@dataclass
|
|
@@ -362,21 +364,23 @@ async def _stdio_stream_from_command_router(
|
|
|
362
364
|
params: _StreamReaderThroughCommandRouterParams,
|
|
363
365
|
) -> AsyncGenerator[bytes, None]:
|
|
364
366
|
"""Stream raw bytes from the router client."""
|
|
365
|
-
|
|
366
|
-
params.
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
367
|
+
async with aclosing(
|
|
368
|
+
params.command_router_client.exec_stdio_read(
|
|
369
|
+
params.task_id, params.object_id, params.file_descriptor, params.deadline
|
|
370
|
+
)
|
|
371
|
+
) as stream:
|
|
372
|
+
try:
|
|
373
|
+
async for item in stream:
|
|
374
|
+
if len(item.data) == 0:
|
|
375
|
+
# This is an error.
|
|
376
|
+
raise ValueError("Received empty message streaming stdio from sandbox.")
|
|
377
|
+
|
|
378
|
+
yield item.data
|
|
379
|
+
except ExecTimeoutError:
|
|
380
|
+
logger.debug(f"Deadline exceeded while streaming stdio for exec {params.object_id}")
|
|
381
|
+
# TODO(saltzm): This is a weird API, but customers currently may rely on it. We
|
|
382
|
+
# should probably raise this error rather than just ending the stream.
|
|
383
|
+
return
|
|
380
384
|
|
|
381
385
|
|
|
382
386
|
class _BytesStreamReaderThroughCommandRouter:
|
|
@@ -404,18 +408,13 @@ class _BytesStreamReaderThroughCommandRouter:
|
|
|
404
408
|
data_bytes += cast(bytes, part)
|
|
405
409
|
return data_bytes
|
|
406
410
|
|
|
407
|
-
def __aiter__(self) ->
|
|
408
|
-
return self
|
|
411
|
+
def __aiter__(self) -> AsyncGenerator[bytes, None]:
|
|
412
|
+
return _stdio_stream_from_command_router(self._params)
|
|
409
413
|
|
|
410
|
-
async def
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
return await self._stream.__anext__()
|
|
415
|
-
|
|
416
|
-
async def aclose(self):
|
|
417
|
-
if self._stream:
|
|
418
|
-
await self._stream.aclose()
|
|
414
|
+
async def _print_all(self, output_stream: TextIO) -> None:
|
|
415
|
+
async for part in self:
|
|
416
|
+
output_stream.buffer.write(part)
|
|
417
|
+
output_stream.buffer.flush()
|
|
419
418
|
|
|
420
419
|
|
|
421
420
|
class _TextStreamReaderThroughCommandRouter:
|
|
@@ -433,7 +432,6 @@ class _TextStreamReaderThroughCommandRouter:
|
|
|
433
432
|
) -> None:
|
|
434
433
|
self._params = params
|
|
435
434
|
self._by_line = by_line
|
|
436
|
-
self._stream = None
|
|
437
435
|
|
|
438
436
|
@property
|
|
439
437
|
def file_descriptor(self) -> int:
|
|
@@ -445,22 +443,21 @@ class _TextStreamReaderThroughCommandRouter:
|
|
|
445
443
|
data_str += cast(str, part)
|
|
446
444
|
return data_str
|
|
447
445
|
|
|
448
|
-
def __aiter__(self) ->
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
async def __anext__(self) -> str:
|
|
452
|
-
if self._stream is None:
|
|
453
|
-
bytes_stream = _stdio_stream_from_command_router(self._params)
|
|
446
|
+
async def __aiter__(self) -> AsyncGenerator[str, None]:
|
|
447
|
+
async with aclosing(_stdio_stream_from_command_router(self._params)) as bytes_stream:
|
|
454
448
|
if self._by_line:
|
|
455
|
-
|
|
449
|
+
stream = _decode_bytes_stream_to_str(_stream_by_line(bytes_stream))
|
|
456
450
|
else:
|
|
457
|
-
|
|
458
|
-
# This raises StopAsyncIteration if the stream is at EOF.
|
|
459
|
-
return await self._stream.__anext__()
|
|
451
|
+
stream = _decode_bytes_stream_to_str(bytes_stream)
|
|
460
452
|
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
453
|
+
async with aclosing(stream):
|
|
454
|
+
async for part in stream:
|
|
455
|
+
yield part
|
|
456
|
+
|
|
457
|
+
async def _print_all(self, output_stream: TextIO) -> None:
|
|
458
|
+
async with aclosing(self.__aiter__()) as stream:
|
|
459
|
+
async for part in stream:
|
|
460
|
+
output_stream.write(part)
|
|
464
461
|
|
|
465
462
|
|
|
466
463
|
class _StdoutPrintingStreamReaderThroughCommandRouter(Generic[T]):
|
|
@@ -479,7 +476,6 @@ class _StdoutPrintingStreamReaderThroughCommandRouter(Generic[T]):
|
|
|
479
476
|
) -> None:
|
|
480
477
|
self._reader = reader
|
|
481
478
|
self._task: Optional[asyncio.Task[None]] = None
|
|
482
|
-
self._closed = False
|
|
483
479
|
# Kick off a background task that reads from the underlying text stream and prints to stdout.
|
|
484
480
|
self._start_printing_task()
|
|
485
481
|
|
|
@@ -490,31 +486,9 @@ class _StdoutPrintingStreamReaderThroughCommandRouter(Generic[T]):
|
|
|
490
486
|
def _start_printing_task(self) -> None:
|
|
491
487
|
async def _run():
|
|
492
488
|
try:
|
|
493
|
-
|
|
494
|
-
def print_text_part(part: Union[str, bytes]) -> None:
|
|
495
|
-
assert isinstance(part, str)
|
|
496
|
-
print(cast(str, part), end="")
|
|
497
|
-
|
|
498
|
-
def print_bytes_part(part: Union[str, bytes]) -> None:
|
|
499
|
-
assert isinstance(part, bytes)
|
|
500
|
-
sys.stdout.buffer.write(cast(bytes, part))
|
|
501
|
-
sys.stdout.buffer.flush()
|
|
502
|
-
|
|
503
|
-
if isinstance(self._reader, _BytesStreamReaderThroughCommandRouter):
|
|
504
|
-
print_part = print_bytes_part
|
|
505
|
-
elif isinstance(self._reader, _TextStreamReaderThroughCommandRouter):
|
|
506
|
-
print_part = print_text_part
|
|
507
|
-
else:
|
|
508
|
-
raise ValueError("Unsupported reader type")
|
|
509
|
-
|
|
510
|
-
async for part in self._reader:
|
|
511
|
-
print_part(part)
|
|
489
|
+
await self._reader._print_all(sys.stdout)
|
|
512
490
|
except Exception as e:
|
|
513
491
|
logger.exception(f"Error printing stream: {e}")
|
|
514
|
-
finally:
|
|
515
|
-
closed, self._closed = self._closed, True
|
|
516
|
-
if not closed:
|
|
517
|
-
await self._reader.aclose()
|
|
518
492
|
|
|
519
493
|
self._task = asyncio.create_task(_run())
|
|
520
494
|
|
|
@@ -533,9 +507,6 @@ class _StdoutPrintingStreamReaderThroughCommandRouter(Generic[T]):
|
|
|
533
507
|
with contextlib.suppress(asyncio.CancelledError):
|
|
534
508
|
await self._task
|
|
535
509
|
self._task = None
|
|
536
|
-
closed, self._closed = self._closed, True
|
|
537
|
-
if not closed:
|
|
538
|
-
await self._reader.aclose()
|
|
539
510
|
|
|
540
511
|
|
|
541
512
|
class _DevnullStreamReader(Generic[T]):
|
|
@@ -578,6 +549,7 @@ class _StreamReader(Generic[T]):
|
|
|
578
549
|
_BytesStreamReaderThroughCommandRouter,
|
|
579
550
|
_StdoutPrintingStreamReaderThroughCommandRouter,
|
|
580
551
|
]
|
|
552
|
+
_read_gen: Optional[AsyncGenerator[T, None]] = None
|
|
581
553
|
|
|
582
554
|
def __init__(
|
|
583
555
|
self,
|
|
@@ -631,21 +603,27 @@ class _StreamReader(Generic[T]):
|
|
|
631
603
|
"""Fetch the entire contents of the stream until EOF."""
|
|
632
604
|
return cast(T, await self._impl.read())
|
|
633
605
|
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
def __aiter__(self) -> AsyncIterator[T]:
|
|
639
|
-
"""mdmd:hidden"""
|
|
640
|
-
return self
|
|
606
|
+
def __aiter__(self) -> AsyncGenerator[T, None]:
|
|
607
|
+
if not self._read_gen:
|
|
608
|
+
self._read_gen = cast(AsyncGenerator[T, None], self._impl.__aiter__())
|
|
609
|
+
return self._read_gen
|
|
641
610
|
|
|
642
611
|
async def __anext__(self) -> T:
|
|
643
|
-
"""
|
|
644
|
-
|
|
612
|
+
"""Deprecated: This exists for backwards compatibility and will be removed in a future version of Modal
|
|
613
|
+
|
|
614
|
+
Only use next/anext on the return value of iter/aiter on the StreamReader object (treat streamreader as
|
|
615
|
+
an iterable, not an iterator).
|
|
616
|
+
"""
|
|
617
|
+
if not self._read_gen:
|
|
618
|
+
self.__aiter__() # initialize the read generator
|
|
619
|
+
assert self._read_gen
|
|
620
|
+
return await self._read_gen.__anext__()
|
|
645
621
|
|
|
646
622
|
async def aclose(self):
|
|
647
623
|
"""mdmd:hidden"""
|
|
648
|
-
|
|
624
|
+
if self._read_gen:
|
|
625
|
+
await self._read_gen.aclose()
|
|
626
|
+
self._read_gen = None
|
|
649
627
|
|
|
650
628
|
|
|
651
629
|
MAX_BUFFER_SIZE = 2 * 1024 * 1024
|
|
@@ -68,11 +68,7 @@ class _StreamReaderThroughServer(typing.Generic[T]):
|
|
|
68
68
|
"""Process logs from the server and yield complete lines only."""
|
|
69
69
|
...
|
|
70
70
|
|
|
71
|
-
def
|
|
72
|
-
async def __anext__(self) -> T:
|
|
73
|
-
"""mdmd:hidden"""
|
|
74
|
-
...
|
|
75
|
-
|
|
71
|
+
def __aiter__(self) -> collections.abc.AsyncGenerator[T, None]: ...
|
|
76
72
|
async def aclose(self):
|
|
77
73
|
"""mdmd:hidden"""
|
|
78
74
|
...
|
|
@@ -90,6 +86,9 @@ def _decode_bytes_stream_to_str(
|
|
|
90
86
|
def _stream_by_line(stream: collections.abc.AsyncGenerator[bytes, None]) -> collections.abc.AsyncGenerator[bytes, None]:
|
|
91
87
|
"""Yield complete lines only (ending with
|
|
92
88
|
), buffering partial lines until complete.
|
|
89
|
+
|
|
90
|
+
When this generator returns, the underlying generator is closed.
|
|
91
|
+
|
|
93
92
|
"""
|
|
94
93
|
...
|
|
95
94
|
|
|
@@ -140,9 +139,8 @@ class _BytesStreamReaderThroughCommandRouter:
|
|
|
140
139
|
@property
|
|
141
140
|
def file_descriptor(self) -> int: ...
|
|
142
141
|
async def read(self) -> bytes: ...
|
|
143
|
-
def __aiter__(self) -> collections.abc.
|
|
144
|
-
async def
|
|
145
|
-
async def aclose(self): ...
|
|
142
|
+
def __aiter__(self) -> collections.abc.AsyncGenerator[bytes, None]: ...
|
|
143
|
+
async def _print_all(self, output_stream: typing.TextIO) -> None: ...
|
|
146
144
|
|
|
147
145
|
class _TextStreamReaderThroughCommandRouter:
|
|
148
146
|
"""StreamReader implementation that will read directly from the worker
|
|
@@ -157,9 +155,8 @@ class _TextStreamReaderThroughCommandRouter:
|
|
|
157
155
|
@property
|
|
158
156
|
def file_descriptor(self) -> int: ...
|
|
159
157
|
async def read(self) -> str: ...
|
|
160
|
-
def __aiter__(self) -> collections.abc.
|
|
161
|
-
async def
|
|
162
|
-
async def aclose(self): ...
|
|
158
|
+
def __aiter__(self) -> collections.abc.AsyncGenerator[str, None]: ...
|
|
159
|
+
async def _print_all(self, output_stream: typing.TextIO) -> None: ...
|
|
163
160
|
|
|
164
161
|
class _StdoutPrintingStreamReaderThroughCommandRouter(typing.Generic[T]):
|
|
165
162
|
"""StreamReader implementation for StreamType.STDOUT when using the task command router.
|
|
@@ -214,6 +211,7 @@ class _StreamReader(typing.Generic[T]):
|
|
|
214
211
|
_BytesStreamReaderThroughCommandRouter,
|
|
215
212
|
_StdoutPrintingStreamReaderThroughCommandRouter,
|
|
216
213
|
]
|
|
214
|
+
_read_gen: typing.Optional[collections.abc.AsyncGenerator[T, None]]
|
|
217
215
|
|
|
218
216
|
def __init__(
|
|
219
217
|
self,
|
|
@@ -240,12 +238,13 @@ class _StreamReader(typing.Generic[T]):
|
|
|
240
238
|
"""Fetch the entire contents of the stream until EOF."""
|
|
241
239
|
...
|
|
242
240
|
|
|
243
|
-
def __aiter__(self) -> collections.abc.
|
|
244
|
-
"""mdmd:hidden"""
|
|
245
|
-
...
|
|
246
|
-
|
|
241
|
+
def __aiter__(self) -> collections.abc.AsyncGenerator[T, None]: ...
|
|
247
242
|
async def __anext__(self) -> T:
|
|
248
|
-
"""
|
|
243
|
+
"""Deprecated: This exists for backwards compatibility and will be removed in a future version of Modal
|
|
244
|
+
|
|
245
|
+
Only use next/anext on the return value of iter/aiter on the StreamReader object (treat streamreader as
|
|
246
|
+
an iterable, not an iterator).
|
|
247
|
+
"""
|
|
249
248
|
...
|
|
250
249
|
|
|
251
250
|
async def aclose(self):
|
|
@@ -383,6 +382,7 @@ class StreamReader(typing.Generic[T]):
|
|
|
383
382
|
_BytesStreamReaderThroughCommandRouter,
|
|
384
383
|
_StdoutPrintingStreamReaderThroughCommandRouter,
|
|
385
384
|
]
|
|
385
|
+
_read_gen: typing.Optional[collections.abc.AsyncGenerator[T, None]]
|
|
386
386
|
|
|
387
387
|
def __init__(
|
|
388
388
|
self,
|
|
@@ -416,20 +416,22 @@ class StreamReader(typing.Generic[T]):
|
|
|
416
416
|
|
|
417
417
|
read: __read_spec[T, typing_extensions.Self]
|
|
418
418
|
|
|
419
|
-
def __iter__(self) -> typing.
|
|
420
|
-
|
|
421
|
-
...
|
|
422
|
-
|
|
423
|
-
def __aiter__(self) -> collections.abc.AsyncIterator[T]:
|
|
424
|
-
"""mdmd:hidden"""
|
|
425
|
-
...
|
|
426
|
-
|
|
419
|
+
def __iter__(self) -> typing.Generator[T, None, None]: ...
|
|
420
|
+
def __aiter__(self) -> collections.abc.AsyncGenerator[T, None]: ...
|
|
427
421
|
def __next__(self) -> T:
|
|
428
|
-
"""
|
|
422
|
+
"""Deprecated: This exists for backwards compatibility and will be removed in a future version of Modal
|
|
423
|
+
|
|
424
|
+
Only use next/anext on the return value of iter/aiter on the StreamReader object (treat streamreader as
|
|
425
|
+
an iterable, not an iterator).
|
|
426
|
+
"""
|
|
429
427
|
...
|
|
430
428
|
|
|
431
429
|
async def __anext__(self) -> T:
|
|
432
|
-
"""
|
|
430
|
+
"""Deprecated: This exists for backwards compatibility and will be removed in a future version of Modal
|
|
431
|
+
|
|
432
|
+
Only use next/anext on the return value of iter/aiter on the StreamReader object (treat streamreader as
|
|
433
|
+
an iterable, not an iterator).
|
|
434
|
+
"""
|
|
433
435
|
...
|
|
434
436
|
|
|
435
437
|
def close(self):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|