import pandas as pd from pydantic import BaseModel, Field, ConfigDict from contracts.RepoContext import Language class DependencyNode(BaseModel): """A single node in the dependency graph.""" model_config = ConfigDict(frozen=True) id: str = Field(..., description="Unique identifier (file path or module name)") label: str = Field(..., description="Human-readable label") language: Language is_external: bool = Field( default=False, description="True if the dependency is outside the repository", ) class DependencyEdge(BaseModel): """A directed edge from source → target (source depends on target).""" source: str = Field(..., description="Node id of the dependant") target: str = Field(..., description="Node id of the dependency") kind: str = Field( default="import", description="Edge kind: import, include, inherit, call, etc.", ) class DependencyGraph(BaseModel): """Complete dependency graph result.""" root: str = Field(..., description="Entrypoint node id") nodes: list[DependencyNode] edges: list[DependencyEdge] metadata: dict[str, str] = Field(default_factory=dict) class AnalyzeResult(BaseModel): """Return shape of :func:`analyze`.""" model_config = ConfigDict(arbitrary_types_allowed=True) df: pd.DataFrame isolated: list[DependencyNode] leaf_no_deps: list[DependencyNode] entry_no_dependents: list[DependencyNode] widely_used: list[tuple[DependencyNode, int]] used_by_packages: dict[DependencyNode, int] wccs: list[set[DependencyNode]] sccs: list[set[DependencyNode]] node2comm: dict[DependencyNode, int] comms: list[set[DependencyNode]]