Contracts
The abstract base classes that extension points implement. They live in
graphlens.contracts and the most common ones are re-exported from the
top-level package.
from graphlens import (
LanguageAdapter,
DependencyFileParser,
GraphBackend,
ProjectReader,
DiscoveredProject,
BoundaryRef,
)
LanguageAdapter
The contract every language adapter implements. See Writing an adapter for a walkthrough.
class LanguageAdapter(ABC):
@abstractmethod
def language(self) -> str: ...
@abstractmethod
def can_handle(self, project_root: str | Path) -> bool: ...
@abstractmethod
def analyze(
self,
project_root: str | Path,
files: list[Path] | None = None,
*,
strict: bool = False,
) -> GraphLens: ...
# Provided defaults:
def file_extensions(self) -> set[str]: ...
def collect_files(self, project_root: str | Path) -> list[Path]: ...
can_handlemust returnTruefor multi-language projects even when the marker file lives in a sub-directory.analyzewithstrict=TrueraisesAdapterErrorwhen the resolver status is notok.collect_fileshas a default implementation driven byfile_extensions().
SymbolResolver
The type-aware resolution backend (in graphlens.contracts.resolver). All
coordinates are 1-based. Implementations must never raise — every method
returns None or [] on failure.
class SymbolResolver(ABC):
@abstractmethod
def prepare(self, project_root: Path, files: list[Path]) -> None: ...
@abstractmethod
def definition_at(self, file: Path, line: int, col: int) -> ResolvedRef | None: ...
@abstractmethod
def infer_type_at(self, file: Path, line: int, col: int) -> ResolvedRef | None: ...
@abstractmethod
def references_to(self, file: Path, line: int, col: int) -> list[Occurrence]: ...
def status(self) -> ResolverStatus: ... # defaults to OK
Supporting dataclasses:
@dataclass
class ResolvedRef:
full_name: str
file_path: str
line: int
col: int
kind: str
origin: str # 'stdlib' | 'internal' | 'third_party' | 'unknown'
@dataclass
class Occurrence:
file_path: str
line: int
col: int
is_definition: bool
access: str
The resolution pass calls definition_at for every occurrence role;
infer_type_at is part of the contract for type inference but is not invoked by
the current pass.
DependencyFileParser
Extracts declared third-party package names from a manifest. One parser per file
format; compose them into a <LANG>_DEFAULT_DEP_PARSERS list.
class DependencyFileParser(ABC):
@abstractmethod
def can_parse(self, project_root: Path) -> bool: ...
@abstractmethod
def parse(self, project_root: Path) -> frozenset[str]: ...
- Include dev/test groups so test imports classify as
third_party. - Return
frozenset()on any error — never raise. - Normalize names with
normalize_pkg_name().
ProjectReader
Discovers projects and enumerates their source files.
class ProjectReader(ABC):
@abstractmethod
def discover(self, root: Path) -> list[DiscoveredProject]: ...
@dataclass
class DiscoveredProject:
root: Path
language: str
files: list[Path] = []
GraphBackend
The persistence contract — implement it to store a graph somewhere (a database, a file, a service).
class GraphBackend(ABC):
@abstractmethod
def store(self, graph: GraphLens) -> None: ...
@abstractmethod
def clear(self) -> None: ...
BoundaryRef
A language-agnostic descriptor of a cross-language port, emitted by adapters
before a BOUNDARY node is created.
@dataclass
class BoundaryRef:
mechanism: str # 'http' | 'grpc' | 'queue' | 'temporal'
role: str # 'server' (exposes) | 'client' (consumes)
key: str # normalized match key, e.g. 'GET /users/{}'
line: int
col: int
confidence: float = 1.0
detail: Mapping[str, str] = {}