Files
graphify/tests
Yyunozor 1292639344 fix(python): keep TYPE_CHECKING-only imports out of import cycles (#3159)
Imports under `if TYPE_CHECKING:` never execute, but the Python extractor
emitted them as ordinary `imports_from` edges, so the Import Cycles section
listed cycles that cannot happen at runtime.

Stamp them `type_only`, the marker find_import_cycles already skips for
TypeScript `import type` (#3123); the edge stays in the graph. Covers
`TYPE_CHECKING` and `<module>.TYPE_CHECKING`, `import x`, `from x import y`,
relative imports and nesting. The `else:` branch and the body of
`if not TYPE_CHECKING:` stay runtime imports.

build_from_json collapses the import edges of one file pair into one, and
dedupe_edges those of one (source, target, relation), keeping the marker of
either side. Stamping alone would let a guarded import mask a runtime one
(for example `from . import b` plus a guarded `from .b import B`) and lose a
real cycle. The collapsed edge is therefore `type_only` only if every import
folded into it is: an import that runs always wins. The same collapse already
hid a real cycle for TypeScript `import type` next to a value import of one
file. In the default undirected graph, the reverse-direction duplicate that
#1061 drops is the other file's import, so it leaves the surviving edge's
marker alone.

Not covered: `from pkg import submodule` under the guard. That edge comes from
the resolution pass and is not stamped, so its cycle is still reported.

Assisted-by: assayer harness on Claude Code (https://github.com/Yyunozor/assayer-memory-mcp)
(cherry picked from commit 685b0fffb5)
2026-10-07 17:26:11 +01:00
..