pryscraper/routers/pipelines.py
cryptorugmunch 2f1eec2f78
Some checks failed
CI / lint (pull_request) Successful in 33s
CI / typecheck (pull_request) Failing after 1m42s
CI / test (pull_request) Failing after 2m33s
CI / security (pull_request) Failing after 39s
CI / gitleaks (pull_request) Successful in 36s
CI / commitlint (pull_request) Failing after 10s
style: ruff format
2026-07-03 18:12:36 +02:00

113 lines
4.2 KiB
Python

"""Pry — Pipelines router (remaining api.py routes).
Auto-extracted from api.py during the router-split refactor.
"""
# SPDX-License-Identifier: MIT
# Copyright (c) 2026 Rug Munch Media LLC
from __future__ import annotations
import logging
from typing import Any
from fastapi import APIRouter, Body
from errors import InvalidRequestError, NotFoundError
logger = logging.getLogger(__name__)
router = APIRouter(tags=["Pipelines"])
@router.get(
"/v1/pipelines/steps", tags=["Pipelines"], summary="List all available pipeline step types"
)
async def list_step_types() -> dict[str, Any]:
"""List all available step types for the visual pipeline builder.
Each step type includes: name, icon, description, required inputs with types,
and expected outputs. A UI renders these as drag-and-drop blocks.
"""
from pipelines import STEP_TYPES
return {"success": True, "data": {"step_types": STEP_TYPES, "total": len(STEP_TYPES)}}
@router.post("/v1/pipelines/validate", tags=["Pipelines"], summary="Validate a pipeline definition")
async def validate_pipeline_endpoint(pipeline: dict[str, Any] = Body(...)) -> dict[str, Any]:
"""Validate a pipeline definition for correctness."""
from pipelines import validate_pipeline
errors = validate_pipeline(pipeline)
return {"success": len(errors) == 0, "data": {"valid": len(errors) == 0, "errors": errors}}
@router.post("/v1/pipelines/run", tags=["Pipelines"], summary="Execute a pipeline")
async def run_pipeline_endpoint(
pipeline: dict[str, Any] = Body(...),
context: dict[str, Any] | None = Body(None),
) -> dict[str, Any]:
"""Execute a pipeline definition.
Steps run sequentially. Each step's output is available as
{{step_id.output_key}} in subsequent step templates.
Example pipeline:
{
"name": "Monitor Competitor Pricing",
"steps": [
{"id": "scrape_amazon", "type": "scrape", "inputs": {"url": "https://amazon.com/product"}},
{"id": "extract", "type": "extract_css", "inputs": {"url": "{{scrape_amazon.url}}", "schema": {...}}},
{"id": "quality", "type": "quality_check", "inputs": {"url": "{{scrape_amazon.url}}", "data": "{{extract.items}}"}},
{"id": "notify", "type": "send_slack", "inputs": {"webhook_url": "https://hooks.slack.com/...", "message": "{{quality.quality_score}}"}},
]
}
"""
from pipelines import run_pipeline, validate_pipeline
errors = validate_pipeline(pipeline)
if errors:
raise InvalidRequestError(f"Pipeline validation failed: {'; '.join(errors)}")
result = await run_pipeline(pipeline, context)
return {"success": not result["failed"], "data": result}
@router.post("/v1/pipelines/save", tags=["Pipelines"], summary="Save a pipeline definition")
async def save_pipeline_endpoint(pipeline: dict[str, Any] = Body(...)) -> dict[str, Any]:
"""Save a pipeline definition for later use."""
from pipelines import save_pipeline
result = save_pipeline(pipeline)
return {"success": result["success"], "data": result}
@router.get("/v1/pipelines", tags=["Pipelines"], summary="List saved pipelines")
async def list_pipelines_endpoint() -> dict[str, Any]:
"""List all saved pipeline definitions."""
from pipelines import list_pipelines
pipelines = list_pipelines()
return {"success": True, "data": {"pipelines": pipelines, "total": len(pipelines)}}
@router.get("/v1/pipelines/{pipeline_id}", tags=["Pipelines"], summary="Get a saved pipeline")
async def get_pipeline_endpoint(pipeline_id: str) -> dict[str, Any]:
"""Get a saved pipeline definition by ID."""
from pipelines import get_pipeline
result = get_pipeline(pipeline_id)
if not result:
raise NotFoundError(f"Pipeline not found: {pipeline_id}")
return {"success": True, "data": result}
@router.delete("/v1/pipelines/{pipeline_id}", tags=["Pipelines"], summary="Delete a saved pipeline")
async def delete_pipeline_endpoint(pipeline_id: str) -> dict[str, Any]:
"""Delete a saved pipeline definition."""
from pipelines import delete_pipeline
success = delete_pipeline(pipeline_id)
if not success:
raise NotFoundError(f"Pipeline not found: {pipeline_id}")
return {"success": True, "data": {"deleted": True}}