modal 1.5.5.dev1__tar.gz → 1.5.5.dev3__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.dev1 → modal-1.5.5.dev3}/PKG-INFO +1 -1
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_container_entrypoint.py +4 -2
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_logs_manager.py +67 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_logs_manager.pyi +167 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_runtime/container_io_manager.py +44 -23
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_runtime/container_io_manager.pyi +10 -5
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/client.pyi +2 -2
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/sandbox.py +53 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/sandbox.pyi +72 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal.egg-info/PKG-INFO +1 -1
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal_version/__init__.py +1 -1
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/pyproject.toml +1 -1
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/LICENSE +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/README.md +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/__init__.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/__main__.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_billing.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_clustered_functions.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_clustered_functions.pyi +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_environments.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_function_variants.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_functions.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_grpc_client.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_image.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_ipython.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_load_context.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_location.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_logs.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_object.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_output/__init__.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_output/manager.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_output/pty.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_output/rich.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_output/status.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_partial_function.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_resolver.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_resources.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_runtime/__init__.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_runtime/asgi.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_runtime/execution_context.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_runtime/execution_context.pyi +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_runtime/gpu_memory_snapshot.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_runtime/task_lifecycle_manager.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_runtime/task_lifecycle_manager.pyi +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_runtime/telemetry.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_runtime/user_code_event_loop.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_runtime/user_code_imports.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_serialization.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_server.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_supports_logs.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_traceback.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_tunnel.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_tunnel.pyi +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_type_manager.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_utils/__init__.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_utils/app_utils.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_utils/async_utils.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_utils/auth_token_manager.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_utils/blob_utils.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_utils/browser_utils.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_utils/bytes_io_segment_payload.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_utils/curl_utils.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_utils/deprecation.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_utils/display_utils.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_utils/docker_utils.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_utils/function_utils.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_utils/git_utils.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_utils/grpc_testing.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_utils/grpc_utils.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_utils/hash_utils.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_utils/http_utils.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_utils/jwt_utils.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_utils/logger.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_utils/mount_utils.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_utils/name_utils.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_utils/package_utils.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_utils/pattern_utils.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_utils/proxy_support.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_utils/rand_pb_testing.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_utils/sandbox_fs_utils.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_utils/shell_utils.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_utils/task_command_router_client.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_utils/time_utils.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_vendor/__init__.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_vendor/a2wsgi_wsgi.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_vendor/cloudpickle.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_vendor/tblib.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_vendor/version.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_watcher.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/_workspace.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/app.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/app.pyi +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/billing.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/billing.pyi +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/builder/2023.12.312.txt +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/builder/2023.12.txt +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/builder/2024.04.txt +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/builder/2024.10.txt +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/builder/2025.06.txt +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/builder/PREVIEW.txt +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/builder/README.md +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/builder/base-images.json +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/call_graph.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/cli/__init__.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/cli/_download.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/cli/_help.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/cli/_traceback.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/cli/app.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/cli/billing.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/cli/bootstrap.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/cli/changelog.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/cli/cluster.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/cli/config.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/cli/container.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/cli/curl.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/cli/dashboard.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/cli/dict.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/cli/endpoint.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/cli/entry_point.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/cli/environment.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/cli/image.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/cli/import_refs.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/cli/launch.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/cli/logo.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/cli/network_file_system.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/cli/profile.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/cli/programs/__init__.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/cli/programs/run_jupyter.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/cli/programs/vscode.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/cli/queues.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/cli/run.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/cli/secret.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/cli/selector.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/cli/shell.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/cli/skills.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/cli/token.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/cli/utils.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/cli/volume.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/cli/workspace.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/client.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/cloud_bucket_mount.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/cloud_bucket_mount.pyi +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/cls.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/cls.pyi +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/config.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/container_process.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/container_process.pyi +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/dict.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/dict.pyi +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/environments.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/environments.pyi +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/exception.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/experimental/__init__.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/experimental/flash.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/experimental/flash.pyi +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/experimental/ipython.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/file_io.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/file_io.pyi +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/file_pattern_matcher.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/functions.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/functions.pyi +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/image.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/image.pyi +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/io_streams.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/io_streams.pyi +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/mount.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/mount.pyi +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/network_file_system.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/network_file_system.pyi +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/object.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/object.pyi +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/output.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/parallel_map.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/parallel_map.pyi +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/partial_function.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/partial_function.pyi +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/proxy.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/proxy.pyi +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/py.typed +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/queue.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/queue.pyi +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/retries.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/runner.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/runner.pyi +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/running_app.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/sandbox_fs.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/sandbox_fs.pyi +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/schedule.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/scheduler_placement.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/secret.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/secret.pyi +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/server.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/server.pyi +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/serving.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/serving.pyi +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/skills/modal/SKILL.md +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/snapshot.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/snapshot.pyi +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/stream_type.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/token_flow.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/token_flow.pyi +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/types.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/volume.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/volume.pyi +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/workspace.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal/workspace.pyi +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal.egg-info/SOURCES.txt +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal.egg-info/dependency_links.txt +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal.egg-info/entry_points.txt +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal.egg-info/requires.txt +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal.egg-info/top_level.txt +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal_docs/__init__.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal_docs/gen_cli_docs.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal_docs/gen_cli_docs_main.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal_docs/gen_reference_docs.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal_docs/gen_reference_docs_main.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal_docs/mdmd/__init__.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal_docs/mdmd/mdmd.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal_docs/mdmd/signatures.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal_docs/mdmd/types.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal_docs/reference_intro.md +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal_proto/__init__.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal_proto/api_grpc.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal_proto/api_pb2.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal_proto/api_pb2.pyi +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal_proto/api_pb2_grpc.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal_proto/api_pb2_grpc.pyi +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal_proto/modal_api_grpc.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal_proto/py.typed +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal_proto/task_command_router_grpc.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal_proto/task_command_router_pb2.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal_proto/task_command_router_pb2.pyi +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal_proto/task_command_router_pb2_grpc.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal_proto/task_command_router_pb2_grpc.pyi +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/modal_version/__main__.py +0 -0
- {modal-1.5.5.dev1 → modal-1.5.5.dev3}/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.dev3",
|
|
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.dev3",
|
|
213
213
|
):
|
|
214
214
|
"""mdmd:hidden
|
|
215
215
|
The Modal client object is not intended to be instantiated directly by users.
|
|
@@ -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."""
|
|
@@ -3,7 +3,9 @@ import collections.abc
|
|
|
3
3
|
import enum
|
|
4
4
|
import google.protobuf.message
|
|
5
5
|
import modal._image
|
|
6
|
+
import modal._logs_manager
|
|
6
7
|
import modal._object
|
|
8
|
+
import modal._supports_logs
|
|
7
9
|
import modal._tunnel
|
|
8
10
|
import modal._utils.task_command_router_client
|
|
9
11
|
import modal.app
|
|
@@ -808,6 +810,14 @@ class _Sandbox(modal._object._Object):
|
|
|
808
810
|
...
|
|
809
811
|
|
|
810
812
|
async def _get_task_id(self, raise_if_task_complete=False) -> str: ...
|
|
813
|
+
async def _resolve_task_id_for_logs(self) -> str:
|
|
814
|
+
"""Try to resolve the task ID in one shot for historical log fetches.
|
|
815
|
+
|
|
816
|
+
For a historical log api, we should not wait for the task to be created.
|
|
817
|
+
If the Sandbox created logs worth fetching, the task ID should be available.
|
|
818
|
+
"""
|
|
819
|
+
...
|
|
820
|
+
|
|
811
821
|
async def _get_command_router_client(
|
|
812
822
|
self, task_id: str
|
|
813
823
|
) -> modal._utils.task_command_router_client.TaskCommandRouterClient: ...
|
|
@@ -1052,6 +1062,25 @@ class _Sandbox(modal._object._Object):
|
|
|
1052
1062
|
"""
|
|
1053
1063
|
...
|
|
1054
1064
|
|
|
1065
|
+
async def _get_log_query_data(self) -> modal._supports_logs._LogQueryData: ...
|
|
1066
|
+
@property
|
|
1067
|
+
def logs(self) -> modal._logs_manager._SandboxLogsManager:
|
|
1068
|
+
"""Access logs for a `Sandbox` entrypoint.
|
|
1069
|
+
|
|
1070
|
+
Useful for inspecting logs after a Sandbox terminates.
|
|
1071
|
+
Use [`fetch()`](#logsfetch)
|
|
1072
|
+
to read logs from a UTC time range, [`tail()`](#logstail)
|
|
1073
|
+
to read the most recent logs.
|
|
1074
|
+
|
|
1075
|
+
Note that the logs from executed commands in the sandbox (via `exec()`) are not included in the
|
|
1076
|
+
entrypoint logs.
|
|
1077
|
+
|
|
1078
|
+
See also:
|
|
1079
|
+
- [`modal app logs`](https://modal.com/docs/cli/latest/app#modal-app-logs):
|
|
1080
|
+
CLI access to logs for an App.
|
|
1081
|
+
"""
|
|
1082
|
+
...
|
|
1083
|
+
|
|
1055
1084
|
class _SidecarContainer:
|
|
1056
1085
|
"""Handle to an additional container running in a Sandbox."""
|
|
1057
1086
|
|
|
@@ -2841,6 +2870,25 @@ class Sandbox(modal.object.Object):
|
|
|
2841
2870
|
|
|
2842
2871
|
_get_task_id: ___get_task_id_spec
|
|
2843
2872
|
|
|
2873
|
+
class ___resolve_task_id_for_logs_spec(typing_extensions.Protocol):
|
|
2874
|
+
def __call__(self, /) -> str:
|
|
2875
|
+
"""Try to resolve the task ID in one shot for historical log fetches.
|
|
2876
|
+
|
|
2877
|
+
For a historical log api, we should not wait for the task to be created.
|
|
2878
|
+
If the Sandbox created logs worth fetching, the task ID should be available.
|
|
2879
|
+
"""
|
|
2880
|
+
...
|
|
2881
|
+
|
|
2882
|
+
async def aio(self, /) -> str:
|
|
2883
|
+
"""Try to resolve the task ID in one shot for historical log fetches.
|
|
2884
|
+
|
|
2885
|
+
For a historical log api, we should not wait for the task to be created.
|
|
2886
|
+
If the Sandbox created logs worth fetching, the task ID should be available.
|
|
2887
|
+
"""
|
|
2888
|
+
...
|
|
2889
|
+
|
|
2890
|
+
_resolve_task_id_for_logs: ___resolve_task_id_for_logs_spec
|
|
2891
|
+
|
|
2844
2892
|
class ___get_command_router_client_spec(typing_extensions.Protocol):
|
|
2845
2893
|
def __call__(self, /, task_id: str) -> modal._utils.task_command_router_client.TaskCommandRouterClient: ...
|
|
2846
2894
|
async def aio(self, /, task_id: str) -> modal._utils.task_command_router_client.TaskCommandRouterClient: ...
|
|
@@ -3349,6 +3397,30 @@ class Sandbox(modal.object.Object):
|
|
|
3349
3397
|
|
|
3350
3398
|
_experimental_list: typing.ClassVar[___experimental_list_spec]
|
|
3351
3399
|
|
|
3400
|
+
class ___get_log_query_data_spec(typing_extensions.Protocol):
|
|
3401
|
+
def __call__(self, /) -> modal._supports_logs._LogQueryData: ...
|
|
3402
|
+
async def aio(self, /) -> modal._supports_logs._LogQueryData: ...
|
|
3403
|
+
|
|
3404
|
+
_get_log_query_data: ___get_log_query_data_spec
|
|
3405
|
+
|
|
3406
|
+
@property
|
|
3407
|
+
def logs(self) -> modal._logs_manager.SandboxLogsManager:
|
|
3408
|
+
"""Access logs for a `Sandbox` entrypoint.
|
|
3409
|
+
|
|
3410
|
+
Useful for inspecting logs after a Sandbox terminates.
|
|
3411
|
+
Use [`fetch()`](#logsfetch)
|
|
3412
|
+
to read logs from a UTC time range, [`tail()`](#logstail)
|
|
3413
|
+
to read the most recent logs.
|
|
3414
|
+
|
|
3415
|
+
Note that the logs from executed commands in the sandbox (via `exec()`) are not included in the
|
|
3416
|
+
entrypoint logs.
|
|
3417
|
+
|
|
3418
|
+
See also:
|
|
3419
|
+
- [`modal app logs`](https://modal.com/docs/cli/latest/app#modal-app-logs):
|
|
3420
|
+
CLI access to logs for an App.
|
|
3421
|
+
"""
|
|
3422
|
+
...
|
|
3423
|
+
|
|
3352
3424
|
_default_image: modal._image._Image
|
|
3353
3425
|
|
|
3354
3426
|
_MAIN_CONTAINER_NAME: str
|