Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions parrant/lineage/display/html/explore.py
Original file line number Diff line number Diff line change
Expand Up @@ -258,8 +258,9 @@ def _setup_templates_and_routes(self) -> None:
@self.app.get("/", response_class=HTMLResponse)
async def home(request: Request) -> Any:
return self.templates.TemplateResponse(
"graph.html",
{"request": request, "data": GraphData().model_dump(), "explore_mode": True},
request=request,
name="graph.html",
context={"data": GraphData().model_dump(), "explore_mode": True},
)

@self.app.get("/api/graph")
Expand Down
53 changes: 50 additions & 3 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,18 @@ mkdocs-click = ">=0.8.1,<0.9.0"
requests = ">=2.32.0,<3.0.0"
types-requests = ">=2.32.0,<3.0.0"
types-pyyaml = "^6.0.12.20260815"
httpx = ">=0.27.0,<1.0.0"

[tool.pytest.ini_options]
pythonpath = ["."]
# Fail tests on any deprecation (e.g. starlette's old TemplateResponse convention, removed
# in 1.6 — issue #139), instead of warning silently until the upstream removal ships to end
# users. If a third-party-internal deprecation we can't fix starts breaking CI, add a scoped
# "ignore:<message>::<module>" entry below the error rules rather than loosening them.
filterwarnings = [
"error::DeprecationWarning",
"error::PendingDeprecationWarning",
]

[tool.black]
line-length = 100
Expand Down
15 changes: 15 additions & 0 deletions tests/e2e/test_lineage_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,21 @@ def collect_resource_types(nodes: list) -> None:
pytest.skip(f"Could not test snapshot lineage endpoint: {e}")


def test_home_page_renders(dbt_artifacts: Dict[str, Any], server_port: int) -> None:
"""The root page must render — it is the only template-rendering route, so API-only
coverage misses it entirely (issue #139 shipped a server that answered every /api/*
call but 500'd on the page users actually open)."""
catalog_path = Path(dbt_artifacts["catalog_path"])
manifest_path = Path(dbt_artifacts["manifest_path"])

with lineage_server(catalog_path, manifest_path, server_port) as port:
response = requests.get(f"http://127.0.0.1:{port}/", timeout=10)

assert response.status_code == 200, f"GET / returned {response.status_code}"
assert "text/html" in response.headers.get("content-type", "")
assert "<title>Parrant</title>" in response.text


def test_coverage_endpoint(dbt_artifacts: Dict[str, Any], server_port: int) -> None:
"""Verify /api/coverage exposes the artifact coverage block to the explorer UI."""
catalog_path = Path(dbt_artifacts["catalog_path"])
Expand Down
22 changes: 22 additions & 0 deletions tests/integration/test_lineage_explorer_integration.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import pytest
from fastapi.testclient import TestClient
from parrant.lineage.display.html.explore import LineageExplorer
from parrant.artifacts.registry import ModelRegistry
from parrant.lineage.service import LineageService
Expand Down Expand Up @@ -64,6 +65,27 @@ def test_html_display_nodes(lineage_service, registry):
), f"Starting model '{start_model_name}' not found in graph nodes"


def test_home_route_renders_explorer_page(lineage_service):
"""GET / — the only route that renders a Jinja2 template — returns the explorer page.

Guards the ``TemplateResponse`` calling convention: starlette 1.6 removed the legacy
``(name, context-with-request)`` shim, turning every page load into
``TypeError: unhashable type: 'dict'`` (issue #139). Runs in-process so the
DeprecationWarning-as-error filter in pyproject.toml catches a deprecated calling
style while it is still just a warning on older starlette."""
explorer = LineageExplorer(host="127.0.0.1", port=8000)
explorer.set_lineage_service(lineage_service)

with TestClient(explorer.app) as client:
response = client.get("/")

assert response.status_code == 200
assert response.headers["content-type"].startswith("text/html")
assert "<title>Parrant</title>" in response.text
# explore_mode context reached the template
assert "explore-panel" in response.text


def test_lineage_includes_impact_summary(lineage_service):
"""Test that the lineage endpoint includes impact_summary in the response."""
lineage_explorer = LineageExplorer(host="127.0.0.1", port=8000)
Expand Down
Loading