modal 1.5.5.dev0__tar.gz → 1.5.5.dev2__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.5.5.dev0 → modal-1.5.5.dev2}/PKG-INFO +1 -1
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_container_entrypoint.py +4 -2
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_logs_manager.py +67 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_logs_manager.pyi +167 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_runtime/container_io_manager.py +44 -23
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_runtime/container_io_manager.pyi +10 -5
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/client.pyi +2 -2
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/functions.pyi +6 -6
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/sandbox.py +53 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/sandbox.pyi +72 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal.egg-info/PKG-INFO +1 -1
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal_version/__init__.py +1 -1
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/pyproject.toml +1 -1
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/LICENSE +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/README.md +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/__init__.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/__main__.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_billing.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_clustered_functions.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_clustered_functions.pyi +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_environments.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_function_variants.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_functions.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_grpc_client.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_image.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_ipython.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_load_context.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_location.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_logs.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_object.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_output/__init__.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_output/manager.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_output/pty.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_output/rich.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_output/status.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_partial_function.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_resolver.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_resources.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_runtime/__init__.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_runtime/asgi.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_runtime/execution_context.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_runtime/execution_context.pyi +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_runtime/gpu_memory_snapshot.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_runtime/task_lifecycle_manager.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_runtime/task_lifecycle_manager.pyi +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_runtime/telemetry.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_runtime/user_code_event_loop.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_runtime/user_code_imports.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_serialization.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_server.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_supports_logs.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_traceback.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_tunnel.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_tunnel.pyi +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_type_manager.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_utils/__init__.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_utils/app_utils.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_utils/async_utils.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_utils/auth_token_manager.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_utils/blob_utils.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_utils/browser_utils.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_utils/bytes_io_segment_payload.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_utils/curl_utils.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_utils/deprecation.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_utils/display_utils.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_utils/docker_utils.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_utils/function_utils.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_utils/git_utils.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_utils/grpc_testing.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_utils/grpc_utils.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_utils/hash_utils.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_utils/http_utils.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_utils/jwt_utils.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_utils/logger.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_utils/mount_utils.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_utils/name_utils.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_utils/package_utils.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_utils/pattern_utils.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_utils/proxy_support.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_utils/rand_pb_testing.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_utils/sandbox_fs_utils.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_utils/shell_utils.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_utils/task_command_router_client.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_utils/time_utils.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_vendor/__init__.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_vendor/a2wsgi_wsgi.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_vendor/cloudpickle.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_vendor/tblib.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_vendor/version.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_watcher.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/_workspace.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/app.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/app.pyi +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/billing.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/billing.pyi +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/builder/2023.12.312.txt +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/builder/2023.12.txt +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/builder/2024.04.txt +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/builder/2024.10.txt +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/builder/2025.06.txt +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/builder/PREVIEW.txt +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/builder/README.md +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/builder/base-images.json +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/call_graph.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/cli/__init__.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/cli/_download.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/cli/_help.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/cli/_traceback.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/cli/app.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/cli/billing.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/cli/bootstrap.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/cli/changelog.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/cli/cluster.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/cli/config.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/cli/container.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/cli/curl.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/cli/dashboard.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/cli/dict.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/cli/endpoint.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/cli/entry_point.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/cli/environment.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/cli/image.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/cli/import_refs.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/cli/launch.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/cli/logo.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/cli/network_file_system.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/cli/profile.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/cli/programs/__init__.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/cli/programs/run_jupyter.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/cli/programs/vscode.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/cli/queues.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/cli/run.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/cli/secret.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/cli/selector.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/cli/shell.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/cli/skills.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/cli/token.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/cli/utils.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/cli/volume.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/cli/workspace.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/client.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/cloud_bucket_mount.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/cloud_bucket_mount.pyi +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/cls.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/cls.pyi +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/config.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/container_process.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/container_process.pyi +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/dict.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/dict.pyi +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/environments.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/environments.pyi +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/exception.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/experimental/__init__.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/experimental/flash.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/experimental/flash.pyi +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/experimental/ipython.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/file_io.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/file_io.pyi +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/file_pattern_matcher.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/functions.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/image.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/image.pyi +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/io_streams.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/io_streams.pyi +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/mount.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/mount.pyi +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/network_file_system.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/network_file_system.pyi +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/object.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/object.pyi +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/output.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/parallel_map.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/parallel_map.pyi +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/partial_function.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/partial_function.pyi +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/proxy.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/proxy.pyi +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/py.typed +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/queue.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/queue.pyi +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/retries.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/runner.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/runner.pyi +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/running_app.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/sandbox_fs.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/sandbox_fs.pyi +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/schedule.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/scheduler_placement.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/secret.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/secret.pyi +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/server.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/server.pyi +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/serving.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/serving.pyi +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/skills/modal/SKILL.md +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/snapshot.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/snapshot.pyi +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/stream_type.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/token_flow.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/token_flow.pyi +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/types.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/volume.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/volume.pyi +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/workspace.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal/workspace.pyi +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal.egg-info/SOURCES.txt +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal.egg-info/dependency_links.txt +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal.egg-info/entry_points.txt +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal.egg-info/requires.txt +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal.egg-info/top_level.txt +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal_docs/__init__.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal_docs/gen_cli_docs.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal_docs/gen_cli_docs_main.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal_docs/gen_reference_docs.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal_docs/gen_reference_docs_main.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal_docs/mdmd/__init__.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal_docs/mdmd/mdmd.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal_docs/mdmd/signatures.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal_docs/mdmd/types.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal_docs/reference_intro.md +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal_proto/__init__.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal_proto/api_grpc.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal_proto/api_pb2.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal_proto/api_pb2.pyi +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal_proto/api_pb2_grpc.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal_proto/api_pb2_grpc.pyi +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal_proto/modal_api_grpc.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal_proto/py.typed +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal_proto/task_command_router_grpc.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal_proto/task_command_router_pb2.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal_proto/task_command_router_pb2.pyi +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal_proto/task_command_router_pb2_grpc.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal_proto/task_command_router_pb2_grpc.pyi +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/modal_version/__main__.py +0 -0
- {modal-1.5.5.dev0 → modal-1.5.5.dev2}/setup.cfg +0 -0
|
@@ -145,7 +145,7 @@ def call_function(
|
|
|
145
145
|
item_count += 1
|
|
146
146
|
|
|
147
147
|
await container_io_manager._send_outputs.aio(
|
|
148
|
-
io_context.output_items_generator_done(started_at, item_count)
|
|
148
|
+
io_context, io_context.output_items_generator_done(started_at, item_count)
|
|
149
149
|
)
|
|
150
150
|
else:
|
|
151
151
|
value = await io_context.call_function_async()
|
|
@@ -182,7 +182,9 @@ def call_function(
|
|
|
182
182
|
container_io_manager._queue_put(generator_queue, value)
|
|
183
183
|
item_count += 1
|
|
184
184
|
|
|
185
|
-
container_io_manager._send_outputs(
|
|
185
|
+
container_io_manager._send_outputs(
|
|
186
|
+
io_context, io_context.output_items_generator_done(started_at, item_count)
|
|
187
|
+
)
|
|
186
188
|
else:
|
|
187
189
|
values = io_context.call_function_sync()
|
|
188
190
|
container_io_manager.push_outputs(io_context, started_at, values)
|
|
@@ -93,6 +93,8 @@ def _entry_context_ids(object_id: str, item: api_pb2.TaskLogs, batch: api_pb2.Ta
|
|
|
93
93
|
]
|
|
94
94
|
case "fc":
|
|
95
95
|
context_ids = [item.input_id or batch.input_id, item.container_id or batch.task_id]
|
|
96
|
+
case "sb":
|
|
97
|
+
context_ids = [item.container_id or batch.task_id]
|
|
96
98
|
case _:
|
|
97
99
|
context_ids = []
|
|
98
100
|
# filter for empty strings, can happen for Server which have function_ids but no input/container
|
|
@@ -802,6 +804,71 @@ class _ImageLogsManager:
|
|
|
802
804
|
ImageLogsManager = synchronize_api(_ImageLogsManager, target_module=__name__)
|
|
803
805
|
|
|
804
806
|
|
|
807
|
+
class _SandboxLogsManager:
|
|
808
|
+
"""mdmd:namespace"""
|
|
809
|
+
|
|
810
|
+
def __init__(self, source: _SupportsLogs):
|
|
811
|
+
"""mdmd:hidden"""
|
|
812
|
+
self._manager = _LogsManager(source)
|
|
813
|
+
|
|
814
|
+
async def fetch(
|
|
815
|
+
self,
|
|
816
|
+
*,
|
|
817
|
+
since: datetime,
|
|
818
|
+
until: datetime | None = None,
|
|
819
|
+
source: LogSource | None = None,
|
|
820
|
+
search_text: str = "",
|
|
821
|
+
) -> AsyncGenerator[LogEntry, None]:
|
|
822
|
+
"""Fetch Sandbox logs corresponding to the date range and filters.
|
|
823
|
+
|
|
824
|
+
Args:
|
|
825
|
+
since: Start date to fetch logs from. Must be in UTC or timezone-naive,
|
|
826
|
+
which is interpreted as local time.
|
|
827
|
+
until: Defaults to current date if None. Must be in UTC or timezone-naive, which is interpreted
|
|
828
|
+
as local time.
|
|
829
|
+
source: Filter by source: 'stdout', 'stderr', or 'system'.
|
|
830
|
+
search_text: Filter by search text.
|
|
831
|
+
|
|
832
|
+
Yields:
|
|
833
|
+
`LogEntry` objects in chronological order.
|
|
834
|
+
|
|
835
|
+
Examples:
|
|
836
|
+
|
|
837
|
+
```python notest
|
|
838
|
+
sandbox = modal.Sandbox.from_name("my-app", "sandbox")
|
|
839
|
+
|
|
840
|
+
for entry in sandbox.logs.fetch(
|
|
841
|
+
since=datetime.now() - timedelta(minutes=25),
|
|
842
|
+
source="stdout",
|
|
843
|
+
):
|
|
844
|
+
print(entry.message, end="")
|
|
845
|
+
```
|
|
846
|
+
"""
|
|
847
|
+
async for log_entry in self._manager.fetch(since=since, until=until, source=source, search_text=search_text):
|
|
848
|
+
yield log_entry
|
|
849
|
+
|
|
850
|
+
async def tail(
|
|
851
|
+
self,
|
|
852
|
+
entries: int = 100,
|
|
853
|
+
*,
|
|
854
|
+
source: LogSource | None = None,
|
|
855
|
+
) -> AsyncGenerator[LogEntry, None]:
|
|
856
|
+
"""Fetch the most recent Sandbox logs.
|
|
857
|
+
|
|
858
|
+
Args:
|
|
859
|
+
entries: The number of log entries to return.
|
|
860
|
+
source: Filter by source: 'stdout', 'stderr', or 'system'.
|
|
861
|
+
|
|
862
|
+
Yields:
|
|
863
|
+
`LogEntry` objects in chronological order.
|
|
864
|
+
"""
|
|
865
|
+
async for log_entry in self._manager.tail(entries, source=source):
|
|
866
|
+
yield log_entry
|
|
867
|
+
|
|
868
|
+
|
|
869
|
+
SandboxLogsManager = synchronize_api(_SandboxLogsManager, target_module=__name__)
|
|
870
|
+
|
|
871
|
+
|
|
805
872
|
class _AppLogsManager:
|
|
806
873
|
"""mdmd:namespace"""
|
|
807
874
|
|
|
@@ -996,6 +996,173 @@ class ImageLogsManager:
|
|
|
996
996
|
|
|
997
997
|
tail: __tail_spec
|
|
998
998
|
|
|
999
|
+
class _SandboxLogsManager:
|
|
1000
|
+
"""mdmd:namespace"""
|
|
1001
|
+
def __init__(self, source: modal._supports_logs._SupportsLogs):
|
|
1002
|
+
"""mdmd:hidden"""
|
|
1003
|
+
...
|
|
1004
|
+
|
|
1005
|
+
def fetch(
|
|
1006
|
+
self,
|
|
1007
|
+
*,
|
|
1008
|
+
since: datetime.datetime,
|
|
1009
|
+
until: typing.Optional[datetime.datetime] = None,
|
|
1010
|
+
source: typing.Optional[typing.Literal["stdout", "stderr", "system"]] = None,
|
|
1011
|
+
search_text: str = "",
|
|
1012
|
+
) -> collections.abc.AsyncGenerator[modal.types.LogEntry, None]:
|
|
1013
|
+
"""Fetch Sandbox logs corresponding to the date range and filters.
|
|
1014
|
+
|
|
1015
|
+
Args:
|
|
1016
|
+
since: Start date to fetch logs from. Must be in UTC or timezone-naive,
|
|
1017
|
+
which is interpreted as local time.
|
|
1018
|
+
until: Defaults to current date if None. Must be in UTC or timezone-naive, which is interpreted
|
|
1019
|
+
as local time.
|
|
1020
|
+
source: Filter by source: 'stdout', 'stderr', or 'system'.
|
|
1021
|
+
search_text: Filter by search text.
|
|
1022
|
+
|
|
1023
|
+
Yields:
|
|
1024
|
+
`LogEntry` objects in chronological order.
|
|
1025
|
+
|
|
1026
|
+
Examples:
|
|
1027
|
+
|
|
1028
|
+
```python notest
|
|
1029
|
+
sandbox = modal.Sandbox.from_name("my-app", "sandbox")
|
|
1030
|
+
|
|
1031
|
+
for entry in sandbox.logs.fetch(
|
|
1032
|
+
since=datetime.now() - timedelta(minutes=25),
|
|
1033
|
+
source="stdout",
|
|
1034
|
+
):
|
|
1035
|
+
print(entry.message, end="")
|
|
1036
|
+
```
|
|
1037
|
+
"""
|
|
1038
|
+
...
|
|
1039
|
+
|
|
1040
|
+
def tail(
|
|
1041
|
+
self, entries: int = 100, *, source: typing.Optional[typing.Literal["stdout", "stderr", "system"]] = None
|
|
1042
|
+
) -> collections.abc.AsyncGenerator[modal.types.LogEntry, None]:
|
|
1043
|
+
"""Fetch the most recent Sandbox logs.
|
|
1044
|
+
|
|
1045
|
+
Args:
|
|
1046
|
+
entries: The number of log entries to return.
|
|
1047
|
+
source: Filter by source: 'stdout', 'stderr', or 'system'.
|
|
1048
|
+
|
|
1049
|
+
Yields:
|
|
1050
|
+
`LogEntry` objects in chronological order.
|
|
1051
|
+
"""
|
|
1052
|
+
...
|
|
1053
|
+
|
|
1054
|
+
class SandboxLogsManager:
|
|
1055
|
+
"""mdmd:namespace"""
|
|
1056
|
+
def __init__(self, source: modal._supports_logs._SupportsLogs):
|
|
1057
|
+
"""mdmd:hidden"""
|
|
1058
|
+
...
|
|
1059
|
+
|
|
1060
|
+
class __fetch_spec(typing_extensions.Protocol):
|
|
1061
|
+
def __call__(
|
|
1062
|
+
self,
|
|
1063
|
+
/,
|
|
1064
|
+
*,
|
|
1065
|
+
since: datetime.datetime,
|
|
1066
|
+
until: typing.Optional[datetime.datetime] = None,
|
|
1067
|
+
source: typing.Optional[typing.Literal["stdout", "stderr", "system"]] = None,
|
|
1068
|
+
search_text: str = "",
|
|
1069
|
+
) -> typing.Generator[modal.types.LogEntry, None, None]:
|
|
1070
|
+
"""Fetch Sandbox logs corresponding to the date range and filters.
|
|
1071
|
+
|
|
1072
|
+
Args:
|
|
1073
|
+
since: Start date to fetch logs from. Must be in UTC or timezone-naive,
|
|
1074
|
+
which is interpreted as local time.
|
|
1075
|
+
until: Defaults to current date if None. Must be in UTC or timezone-naive, which is interpreted
|
|
1076
|
+
as local time.
|
|
1077
|
+
source: Filter by source: 'stdout', 'stderr', or 'system'.
|
|
1078
|
+
search_text: Filter by search text.
|
|
1079
|
+
|
|
1080
|
+
Yields:
|
|
1081
|
+
`LogEntry` objects in chronological order.
|
|
1082
|
+
|
|
1083
|
+
Examples:
|
|
1084
|
+
|
|
1085
|
+
```python notest
|
|
1086
|
+
sandbox = modal.Sandbox.from_name("my-app", "sandbox")
|
|
1087
|
+
|
|
1088
|
+
for entry in sandbox.logs.fetch(
|
|
1089
|
+
since=datetime.now() - timedelta(minutes=25),
|
|
1090
|
+
source="stdout",
|
|
1091
|
+
):
|
|
1092
|
+
print(entry.message, end="")
|
|
1093
|
+
```
|
|
1094
|
+
"""
|
|
1095
|
+
...
|
|
1096
|
+
|
|
1097
|
+
def aio(
|
|
1098
|
+
self,
|
|
1099
|
+
/,
|
|
1100
|
+
*,
|
|
1101
|
+
since: datetime.datetime,
|
|
1102
|
+
until: typing.Optional[datetime.datetime] = None,
|
|
1103
|
+
source: typing.Optional[typing.Literal["stdout", "stderr", "system"]] = None,
|
|
1104
|
+
search_text: str = "",
|
|
1105
|
+
) -> collections.abc.AsyncGenerator[modal.types.LogEntry, None]:
|
|
1106
|
+
"""Fetch Sandbox logs corresponding to the date range and filters.
|
|
1107
|
+
|
|
1108
|
+
Args:
|
|
1109
|
+
since: Start date to fetch logs from. Must be in UTC or timezone-naive,
|
|
1110
|
+
which is interpreted as local time.
|
|
1111
|
+
until: Defaults to current date if None. Must be in UTC or timezone-naive, which is interpreted
|
|
1112
|
+
as local time.
|
|
1113
|
+
source: Filter by source: 'stdout', 'stderr', or 'system'.
|
|
1114
|
+
search_text: Filter by search text.
|
|
1115
|
+
|
|
1116
|
+
Yields:
|
|
1117
|
+
`LogEntry` objects in chronological order.
|
|
1118
|
+
|
|
1119
|
+
Examples:
|
|
1120
|
+
|
|
1121
|
+
```python notest
|
|
1122
|
+
sandbox = modal.Sandbox.from_name("my-app", "sandbox")
|
|
1123
|
+
|
|
1124
|
+
for entry in sandbox.logs.fetch(
|
|
1125
|
+
since=datetime.now() - timedelta(minutes=25),
|
|
1126
|
+
source="stdout",
|
|
1127
|
+
):
|
|
1128
|
+
print(entry.message, end="")
|
|
1129
|
+
```
|
|
1130
|
+
"""
|
|
1131
|
+
...
|
|
1132
|
+
|
|
1133
|
+
fetch: __fetch_spec
|
|
1134
|
+
|
|
1135
|
+
class __tail_spec(typing_extensions.Protocol):
|
|
1136
|
+
def __call__(
|
|
1137
|
+
self, /, entries: int = 100, *, source: typing.Optional[typing.Literal["stdout", "stderr", "system"]] = None
|
|
1138
|
+
) -> typing.Generator[modal.types.LogEntry, None, None]:
|
|
1139
|
+
"""Fetch the most recent Sandbox logs.
|
|
1140
|
+
|
|
1141
|
+
Args:
|
|
1142
|
+
entries: The number of log entries to return.
|
|
1143
|
+
source: Filter by source: 'stdout', 'stderr', or 'system'.
|
|
1144
|
+
|
|
1145
|
+
Yields:
|
|
1146
|
+
`LogEntry` objects in chronological order.
|
|
1147
|
+
"""
|
|
1148
|
+
...
|
|
1149
|
+
|
|
1150
|
+
def aio(
|
|
1151
|
+
self, /, entries: int = 100, *, source: typing.Optional[typing.Literal["stdout", "stderr", "system"]] = None
|
|
1152
|
+
) -> collections.abc.AsyncGenerator[modal.types.LogEntry, None]:
|
|
1153
|
+
"""Fetch the most recent Sandbox logs.
|
|
1154
|
+
|
|
1155
|
+
Args:
|
|
1156
|
+
entries: The number of log entries to return.
|
|
1157
|
+
source: Filter by source: 'stdout', 'stderr', or 'system'.
|
|
1158
|
+
|
|
1159
|
+
Yields:
|
|
1160
|
+
`LogEntry` objects in chronological order.
|
|
1161
|
+
"""
|
|
1162
|
+
...
|
|
1163
|
+
|
|
1164
|
+
tail: __tail_spec
|
|
1165
|
+
|
|
999
1166
|
class _AppLogsManager:
|
|
1000
1167
|
"""mdmd:namespace"""
|
|
1001
1168
|
def __init__(self, source: modal._supports_logs._SupportsLogs):
|
|
@@ -96,6 +96,7 @@ class IOContext:
|
|
|
96
96
|
|
|
97
97
|
_cancel_issued: bool = False
|
|
98
98
|
_cancel_callback: Callable[[], None] | None = None
|
|
99
|
+
_exited: bool = False
|
|
99
100
|
|
|
100
101
|
def __init__(
|
|
101
102
|
self,
|
|
@@ -889,25 +890,35 @@ class _ContainerIOManager:
|
|
|
889
890
|
if item.kill_switch:
|
|
890
891
|
logger.debug(f"Task {self.task_id} input kill signal input.")
|
|
891
892
|
return
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
893
|
+
live_io_context = self.current_inputs.get(item.input_id)
|
|
894
|
+
if live_io_context is not None and (
|
|
895
|
+
live_io_context.retry_counts[live_io_context.input_ids.index(item.input_id)]
|
|
896
|
+
== item.retry_count
|
|
897
|
+
):
|
|
898
|
+
# An expired fetch lease redelivers a still-running attempt under the same
|
|
899
|
+
# input id and retry count; a retry of a failed attempt gets a new retry count.
|
|
900
|
+
logger.warning(f"Skipping duplicate delivery of input {item.input_id}")
|
|
901
|
+
else:
|
|
902
|
+
inputs.append(
|
|
903
|
+
(
|
|
904
|
+
item.input_id,
|
|
905
|
+
item.retry_count,
|
|
906
|
+
item.function_call_id,
|
|
907
|
+
item.attempt_token,
|
|
908
|
+
item.input,
|
|
909
|
+
item.function_call_invocation_type,
|
|
910
|
+
)
|
|
900
911
|
)
|
|
901
|
-
)
|
|
902
912
|
if item.input.final_input:
|
|
903
913
|
if request.batch_max_size > 0:
|
|
904
914
|
logger.debug(f"Task {self.task_id} Final input not expected in batch input stream")
|
|
905
915
|
final_input_received = True
|
|
906
916
|
break
|
|
907
917
|
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
918
|
+
if inputs:
|
|
919
|
+
# If yielded, allow input slots to be released via exit_context
|
|
920
|
+
yield inputs
|
|
921
|
+
yielded = True
|
|
911
922
|
|
|
912
923
|
# TODO(michael): Remove use of max_inputs after worker rollover
|
|
913
924
|
single_use_container = self.function_def.single_use_containers or self.function_def.max_inputs == 1
|
|
@@ -950,7 +961,7 @@ class _ContainerIOManager:
|
|
|
950
961
|
# collect all active input slots, meaning all inputs have wrapped up.
|
|
951
962
|
await self._input_slots.close()
|
|
952
963
|
|
|
953
|
-
async def _send_outputs(self, outputs: list[api_pb2.FunctionPutOutputsItem]) -> None:
|
|
964
|
+
async def _send_outputs(self, io_context: IOContext, outputs: list[api_pb2.FunctionPutOutputsItem]) -> None:
|
|
954
965
|
"""Send pre-built output items with retry and chunking."""
|
|
955
966
|
# There are multiple outputs for a single IOContext in the case of @modal.batched.
|
|
956
967
|
# Limit the batch size to 20 to stay within message size limits and buffer size limits.
|
|
@@ -963,8 +974,7 @@ class _ContainerIOManager:
|
|
|
963
974
|
max_retries=None, # Retry indefinitely, trying every 1s.
|
|
964
975
|
),
|
|
965
976
|
)
|
|
966
|
-
|
|
967
|
-
self.exit_context(input_ids)
|
|
977
|
+
self.exit_context(io_context)
|
|
968
978
|
|
|
969
979
|
@asynccontextmanager
|
|
970
980
|
async def handle_input_exception(
|
|
@@ -984,7 +994,7 @@ class _ContainerIOManager:
|
|
|
984
994
|
raise
|
|
985
995
|
except (InputCancellation, asyncio.CancelledError):
|
|
986
996
|
outputs = await io_context.output_items_cancellation(started_at)
|
|
987
|
-
await self._send_outputs(outputs)
|
|
997
|
+
await self._send_outputs(io_context, outputs)
|
|
988
998
|
logger.warning(f"Successfully canceled input {io_context.input_ids}")
|
|
989
999
|
return
|
|
990
1000
|
except BaseException as exc:
|
|
@@ -995,13 +1005,24 @@ class _ContainerIOManager:
|
|
|
995
1005
|
# print exception so it's logged
|
|
996
1006
|
print_exception(*sys.exc_info())
|
|
997
1007
|
outputs = await io_context.output_items_exception(started_at, self.task_id, exc)
|
|
998
|
-
await self._send_outputs(outputs)
|
|
1008
|
+
await self._send_outputs(io_context, outputs)
|
|
999
1009
|
|
|
1000
|
-
def exit_context(self,
|
|
1001
|
-
for
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1010
|
+
def exit_context(self, io_context: IOContext):
|
|
1011
|
+
# A cancellation can land after outputs were already sent, re-entering here for the same
|
|
1012
|
+
# context; exit at most once so the input slot is not released twice.
|
|
1013
|
+
if io_context._exited:
|
|
1014
|
+
return
|
|
1015
|
+
io_context._exited = True
|
|
1016
|
+
try:
|
|
1017
|
+
for input_id in io_context.input_ids:
|
|
1018
|
+
# A retry admitted before its predecessor finished exiting takes over the
|
|
1019
|
+
# tracking entry, so remove it only if this context still owns it.
|
|
1020
|
+
if self.current_inputs.get(input_id) is io_context:
|
|
1021
|
+
self.current_inputs.pop(input_id)
|
|
1022
|
+
else:
|
|
1023
|
+
logger.warning(f"Input {input_id} missing from active input tracking")
|
|
1024
|
+
finally:
|
|
1025
|
+
self._input_slots.release()
|
|
1005
1026
|
|
|
1006
1027
|
# skip inspection of user-generated output_data for synchronicity input translation
|
|
1007
1028
|
@synchronizer.no_io_translation
|
|
@@ -1013,7 +1034,7 @@ class _ContainerIOManager:
|
|
|
1013
1034
|
) -> None:
|
|
1014
1035
|
# The standard output encoding+sending method for successful function outputs
|
|
1015
1036
|
outputs = await io_context.output_items(started_at, output_data)
|
|
1016
|
-
await self._send_outputs(outputs)
|
|
1037
|
+
await self._send_outputs(io_context, outputs)
|
|
1017
1038
|
|
|
1018
1039
|
@asynccontextmanager
|
|
1019
1040
|
async def snapshot_context_manager(self) -> AsyncGenerator[None, None]:
|
|
@@ -33,6 +33,7 @@ class IOContext:
|
|
|
33
33
|
finalized_function: modal._runtime.user_code_imports.FinalizedFunction
|
|
34
34
|
_cancel_issued: bool
|
|
35
35
|
_cancel_callback: typing.Optional[collections.abc.Callable[[], None]]
|
|
36
|
+
_exited: bool
|
|
36
37
|
|
|
37
38
|
def __init__(
|
|
38
39
|
self,
|
|
@@ -202,7 +203,9 @@ class _ContainerIOManager:
|
|
|
202
203
|
batch_max_size: int = 0,
|
|
203
204
|
batch_wait_ms: int = 0,
|
|
204
205
|
) -> collections.abc.AsyncIterator[IOContext]: ...
|
|
205
|
-
async def _send_outputs(
|
|
206
|
+
async def _send_outputs(
|
|
207
|
+
self, io_context: IOContext, outputs: list[modal_proto.api_pb2.FunctionPutOutputsItem]
|
|
208
|
+
) -> None:
|
|
206
209
|
"""Send pre-built output items with retry and chunking."""
|
|
207
210
|
...
|
|
208
211
|
|
|
@@ -210,7 +213,7 @@ class _ContainerIOManager:
|
|
|
210
213
|
"""Handle an exception while processing a function input."""
|
|
211
214
|
...
|
|
212
215
|
|
|
213
|
-
def exit_context(self,
|
|
216
|
+
def exit_context(self, io_context: IOContext): ...
|
|
214
217
|
async def push_outputs(self, io_context: IOContext, started_at: float, output_data: list[typing.Any]) -> None: ...
|
|
215
218
|
def snapshot_context_manager(self) -> typing.AsyncContextManager[None]: ...
|
|
216
219
|
async def interact(self, from_breakpoint: bool = False): ...
|
|
@@ -445,11 +448,13 @@ class ContainerIOManager:
|
|
|
445
448
|
run_inputs_outputs: __run_inputs_outputs_spec
|
|
446
449
|
|
|
447
450
|
class ___send_outputs_spec(typing_extensions.Protocol):
|
|
448
|
-
def __call__(self, /, outputs: list[modal_proto.api_pb2.FunctionPutOutputsItem]) -> None:
|
|
451
|
+
def __call__(self, /, io_context: IOContext, outputs: list[modal_proto.api_pb2.FunctionPutOutputsItem]) -> None:
|
|
449
452
|
"""Send pre-built output items with retry and chunking."""
|
|
450
453
|
...
|
|
451
454
|
|
|
452
|
-
async def aio(
|
|
455
|
+
async def aio(
|
|
456
|
+
self, /, io_context: IOContext, outputs: list[modal_proto.api_pb2.FunctionPutOutputsItem]
|
|
457
|
+
) -> None:
|
|
453
458
|
"""Send pre-built output items with retry and chunking."""
|
|
454
459
|
...
|
|
455
460
|
|
|
@@ -468,7 +473,7 @@ class ContainerIOManager:
|
|
|
468
473
|
|
|
469
474
|
handle_input_exception: __handle_input_exception_spec
|
|
470
475
|
|
|
471
|
-
def exit_context(self,
|
|
476
|
+
def exit_context(self, io_context: IOContext): ...
|
|
472
477
|
|
|
473
478
|
class __push_outputs_spec(typing_extensions.Protocol):
|
|
474
479
|
def __call__(self, /, io_context: IOContext, started_at: float, output_data: list[typing.Any]) -> None: ...
|
|
@@ -38,7 +38,7 @@ class _Client:
|
|
|
38
38
|
server_url: str,
|
|
39
39
|
client_type: int,
|
|
40
40
|
credentials: typing.Optional[tuple[str, str]],
|
|
41
|
-
version: str = "1.5.5.
|
|
41
|
+
version: str = "1.5.5.dev2",
|
|
42
42
|
):
|
|
43
43
|
"""mdmd:hidden
|
|
44
44
|
The Modal client object is not intended to be instantiated directly by users.
|
|
@@ -209,7 +209,7 @@ class Client:
|
|
|
209
209
|
server_url: str,
|
|
210
210
|
client_type: int,
|
|
211
211
|
credentials: typing.Optional[tuple[str, str]],
|
|
212
|
-
version: str = "1.5.5.
|
|
212
|
+
version: str = "1.5.5.dev2",
|
|
213
213
|
):
|
|
214
214
|
"""mdmd:hidden
|
|
215
215
|
The Modal client object is not intended to be instantiated directly by users.
|
|
@@ -546,7 +546,7 @@ class Function(
|
|
|
546
546
|
|
|
547
547
|
_call_generator: ___call_generator_spec
|
|
548
548
|
|
|
549
|
-
class __remote_spec(typing_extensions.Protocol[
|
|
549
|
+
class __remote_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER]):
|
|
550
550
|
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> ReturnType_INNER:
|
|
551
551
|
"""Calls the function remotely, executing it with the given arguments and returning the execution's result.
|
|
552
552
|
|
|
@@ -571,7 +571,7 @@ class Function(
|
|
|
571
571
|
"""
|
|
572
572
|
...
|
|
573
573
|
|
|
574
|
-
remote: __remote_spec[modal._functions.
|
|
574
|
+
remote: __remote_spec[modal._functions.ReturnType, modal._functions.P]
|
|
575
575
|
|
|
576
576
|
class __remote_gen_spec(typing_extensions.Protocol):
|
|
577
577
|
def __call__(self, /, *args, **kwargs) -> typing.Generator[typing.Any, None, None]:
|
|
@@ -621,7 +621,7 @@ class Function(
|
|
|
621
621
|
"""
|
|
622
622
|
...
|
|
623
623
|
|
|
624
|
-
class ___experimental_spawn_spec(typing_extensions.Protocol[
|
|
624
|
+
class ___experimental_spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER]):
|
|
625
625
|
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
|
|
626
626
|
"""[Experimental] Calls the function with the given arguments, without waiting for the results.
|
|
627
627
|
|
|
@@ -654,7 +654,7 @@ class Function(
|
|
|
654
654
|
"""
|
|
655
655
|
...
|
|
656
656
|
|
|
657
|
-
_experimental_spawn: ___experimental_spawn_spec[modal._functions.
|
|
657
|
+
_experimental_spawn: ___experimental_spawn_spec[modal._functions.ReturnType, modal._functions.P]
|
|
658
658
|
|
|
659
659
|
class ___spawn_map_inner_spec(typing_extensions.Protocol[P_INNER]):
|
|
660
660
|
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> None: ...
|
|
@@ -662,7 +662,7 @@ class Function(
|
|
|
662
662
|
|
|
663
663
|
_spawn_map_inner: ___spawn_map_inner_spec[modal._functions.P]
|
|
664
664
|
|
|
665
|
-
class __spawn_spec(typing_extensions.Protocol[
|
|
665
|
+
class __spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER]):
|
|
666
666
|
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
|
|
667
667
|
"""Calls the function with the given arguments, without waiting for the results.
|
|
668
668
|
|
|
@@ -695,7 +695,7 @@ class Function(
|
|
|
695
695
|
"""
|
|
696
696
|
...
|
|
697
697
|
|
|
698
|
-
spawn: __spawn_spec[modal._functions.
|
|
698
|
+
spawn: __spawn_spec[modal._functions.ReturnType, modal._functions.P]
|
|
699
699
|
|
|
700
700
|
def get_raw_f(self) -> collections.abc.Callable[..., typing.Any]:
|
|
701
701
|
"""Return the inner Python object wrapped by this Modal Function.
|
|
@@ -15,6 +15,8 @@ from dataclasses import dataclass
|
|
|
15
15
|
from pathlib import PurePosixPath
|
|
16
16
|
from typing import TYPE_CHECKING, Any, Literal, Union, overload
|
|
17
17
|
|
|
18
|
+
from modal._logs_manager import _SandboxLogsManager
|
|
19
|
+
from modal._supports_logs import LogsFilters, _LogQueryData
|
|
18
20
|
from modal.secret import _split_env_dict_and_resolvable_secrets
|
|
19
21
|
|
|
20
22
|
from ._output.pty import get_pty_info
|
|
@@ -1931,6 +1933,27 @@ class _Sandbox(_Object, type_prefix="sb"):
|
|
|
1931
1933
|
await asyncio.sleep(0.5)
|
|
1932
1934
|
return self._task_id
|
|
1933
1935
|
|
|
1936
|
+
async def _resolve_task_id_for_logs(self) -> str:
|
|
1937
|
+
"""Try to resolve the task ID in one shot for historical log fetches.
|
|
1938
|
+
|
|
1939
|
+
For a historical log api, we should not wait for the task to be created.
|
|
1940
|
+
If the Sandbox created logs worth fetching, the task ID should be available.
|
|
1941
|
+
"""
|
|
1942
|
+
if self._task_id:
|
|
1943
|
+
return self._task_id
|
|
1944
|
+
|
|
1945
|
+
req = api_pb2.SandboxGetTaskIdRequest(sandbox_id=self.object_id)
|
|
1946
|
+
stub = self.__client.stub
|
|
1947
|
+
if self._is_v2:
|
|
1948
|
+
assert self.__client._auth_token_manager
|
|
1949
|
+
auth_token = await self.__client._auth_token_manager.get_token()
|
|
1950
|
+
resp = await stub.SandboxGetTaskIdV2(req, metadata=[("x-modal-auth-token", auth_token)])
|
|
1951
|
+
else:
|
|
1952
|
+
resp = await stub.SandboxGetTaskId(req)
|
|
1953
|
+
if not resp.task_id:
|
|
1954
|
+
raise ExecutionError("Sandbox task_id is not available yet.")
|
|
1955
|
+
return resp.task_id
|
|
1956
|
+
|
|
1934
1957
|
async def _get_command_router_client(self, task_id: str) -> TaskCommandRouterClient:
|
|
1935
1958
|
if self._command_router_client is None:
|
|
1936
1959
|
try:
|
|
@@ -2605,6 +2628,36 @@ class _Sandbox(_Object, type_prefix="sb"):
|
|
|
2605
2628
|
# Fetch the next batch starting from the end of the current one.
|
|
2606
2629
|
before_timestamp = resp.sandboxes[-1].created_at
|
|
2607
2630
|
|
|
2631
|
+
async def _get_log_query_data(self) -> _LogQueryData:
|
|
2632
|
+
if not self._app_id:
|
|
2633
|
+
if not self._attached:
|
|
2634
|
+
raise ExecutionError("Cannot fetch logs for a detached Sandbox without hydrated app_id")
|
|
2635
|
+
await self.hydrate()
|
|
2636
|
+
|
|
2637
|
+
if not self._app_id:
|
|
2638
|
+
raise ExecutionError("app_id should have been set during sandbox hydration")
|
|
2639
|
+
|
|
2640
|
+
task_id = await self._resolve_task_id_for_logs()
|
|
2641
|
+
return _LogQueryData(self.__client, self._app_id, LogsFilters(task_id=task_id), self.object_id)
|
|
2642
|
+
|
|
2643
|
+
@property
|
|
2644
|
+
def logs(self) -> _SandboxLogsManager:
|
|
2645
|
+
"""Access logs for a `Sandbox` entrypoint.
|
|
2646
|
+
|
|
2647
|
+
Useful for inspecting logs after a Sandbox terminates.
|
|
2648
|
+
Use [`fetch()`](#logsfetch)
|
|
2649
|
+
to read logs from a UTC time range, [`tail()`](#logstail)
|
|
2650
|
+
to read the most recent logs.
|
|
2651
|
+
|
|
2652
|
+
Note that the logs from executed commands in the sandbox (via `exec()`) are not included in the
|
|
2653
|
+
entrypoint logs.
|
|
2654
|
+
|
|
2655
|
+
See also:
|
|
2656
|
+
- [`modal app logs`](https://modal.com/docs/cli/latest/app#modal-app-logs):
|
|
2657
|
+
CLI access to logs for an App.
|
|
2658
|
+
"""
|
|
2659
|
+
return _SandboxLogsManager(self)
|
|
2660
|
+
|
|
2608
2661
|
|
|
2609
2662
|
class _SidecarContainer:
|
|
2610
2663
|
"""Handle to an additional container running in a Sandbox."""
|