JB

Project 01 · 2026

TraceGraph

A static analyzer that parses every module in a Python project, resolves its imports into a directed graph, and uses that graph to catch circular imports before they crash at runtime — and to pick out exactly which tests a code change can affect.

PythonastTarjan SCCpytestcoverage.py

Deep-dive video — coming soon

TraceGraph

Highlights

  • Resolves relative, dynamic, and TYPE_CHECKING imports into a directed module graph; dynamic imports it can't resolve are reported as explicit blind spots, never silently dropped.

  • Every edge carries context (module, function, type-checking) and binding (module vs. symbol) tags, so cycle detection can tell benign cycles from the ones that actually raise ImportError on a partially initialized module.

  • Iterative Tarjan SCC detection over load-time edges uncovered a type-checking misclassification affecting 41 imports in Flask.

  • Test impact analysis over reverse dependencies, validated against coverage.py ground truth on Flask (491 tests) and Requests (635 tests) — 100% recall, zero false negatives, with 8–34% test suite reduction.

Why I built it

Python lets you import almost anything from almost anywhere — until the day two modules need each other at load time and the whole app dies with an ImportError on a half-initialized module. The frustrating part is that most import cycles are actually fine: Python tolerates cycles that only pass module objects around. The dangerous ones are those where load-time code reaches into another module's namespace before it exists.

TraceGraph is built around that distinction. It parses every file with Python's own ast module, resolves each import to a real module in the project, and tags each edge with when the dependency is realized (at import time, inside a function, or only for type checkers) and what it binds (the module object, or symbols out of its namespace). A cycle is only flagged when it runs through at least one load-time symbol edge — the pattern that can actually blow up.

Test impact analysis

The same graph, walked in reverse, answers a second question: if I change this file, which tests do I need to run? TraceGraph selects every test module with a dependency path to the changed file.

Claims like that are easy to make and hard to trust, so the selection is validated empirically. A harness runs a target project's real test suite under coverage.py with one dynamic context per test, giving ground truth for which tests actually executed each module. Against Flask (491 tests) and Requests (635 tests), TraceGraph's static prediction achieved recall 1.00 — it never missed a test that mattered — while cutting the suite by 8–34% depending on how the project's fixtures are wired.