SkillAgentSearch skills...

Pyan

The Python static call graph generator. pyan3 on PyPI. Official development repo.

Install / Use

/learn @Technologicat/Pyan
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Pyan3

Offline call graph generator for Python 3

100% Python supported language versions supported implementations CI status codecov version on PyPI PyPI package format dependency status license: GPL v2+ open issues PRs welcome

For my stance on AI contributions, see the collaboration guidelines.

We use semantic versioning.

Pyan takes one or more Python source files, performs a (rather superficial) static analysis, and constructs a directed graph of the objects in the combined source, and how they define or use each other. The graph can be output for rendering by GraphViz or yEd, or as a plain-text dependency list.

This project has 2 official repositories:

The PyPI package pyan3 is built from development

Note

The static analysis approach Pyan takes is different from running the code and seeing which functions are called and how often. There are various tools that will generate a call graph that way, usually using a debugger or profiling trace hooks, such as Python Call Graph.

Instead, Pyan reads through the source code, and makes deductions from its structure.

Revived! [February 2026]

Pyan3 is back in development. The analyzer has been modernized and tested on Python 3.10–3.14, with fixes for all modern syntax (walrus operator, match statements, async with, type aliases, and more). The plan is to keep Pyan3 up to date with new language releases.

What's new in the revival:

  • Full support for Python 3.10–3.14 syntax
  • Module-level import dependency analysis (--module-level flag and create_modulegraph() API), with import cycle detection
  • Graph depth control (--depth), directional filtering (--direction), call path listing (--paths-from/--paths-to)
  • Comprehensive test suite (200+ tests, 91% branch coverage)
  • Modernized build system and dependencies

This revival was carried out by Technologicat with Claude (Anthropic) as AI pair programmer. See AUTHORS.md for the full contributor history.

<!-- markdown-toc start - Don't edit this section. Run M-x markdown-toc-refresh-toc -->

Table of Contents

<!-- markdown-toc end -->

Overview

<!-- To regenerate graph0: pyan3 tests/orbital/*.py --dot --colored --no-defines --concentrate --file graph0.dot dot -Tsvg graph0.dot -o graph0.svg dot -Tpng graph0.dot -o graph0.png rm graph0.dot -->

Example output

This example was rendered with the recommended options: --colored --no-defines --concentrate.

Uses relations are drawn with black solid arrows. Recursion is indicated by an arrow from a node to itself. Mutual recursion between nodes X and Y is indicated by a pair of arrows, one pointing from X to Y, and the other from Y to X. With --concentrate, bidirectional edges are merged into double-headed arrows.

Defines relations (drawn with dotted gray arrows) can be enabled with --defines.

Nodes are always filled, and made translucent to clearly show any arrows passing underneath them. This is especially useful for large graphs with GraphViz's fdp filter. If colored output is not enabled, the fill is white.

In node coloring, the HSL color model is used. The hue is determined by the filename the node comes from. The lightness is determined by depth of namespace nesting, with darker meaning more deeply nested. Saturation is constant. The spacing between different hues depends on the number of files analyzed; better results are obtained for fewer files.

Groups can be enabled with --grouped (and --nested-groups for nested subgraph clusters). Groups are filled with translucent gray to avoid clashes with any node color.

The nodes can be annotated by filename and source line number information.

Usage

Both CLI and Python API modes are available.

CLI usage

See pyan3 --help.

Basic examples:

# Generate DOT, then render with GraphViz
pyan3 *.py --uses --no-defines --colored --grouped --annotated --dot >myuses.dot
dot -Tsvg myuses.dot >myuses.svg

# Pass a directory — auto-globs **/*.py
pyan3 src/ --dot --colored --grouped >project.dot

# Generate SVG / HTML directly
pyan3 *.py --uses --no-defines --colored --grouped --annotated --svg >myuses.svg
pyan3 *.py --uses --no-defines --colored --grouped --annotated --html >myuses.html

# Output plain text — especially useful for feeding call graph info to coding AI agents
pyan3 src/ --uses --no-defines --text

Recommended options

For a clean uses-only call graph:

pyan3 src/*.py --dot --colored --no-defines --concentrate --file output.dot
dot -Tsvg output.dot -o output.svg

This omits defines edges (which tend to clutter the graph) and merges bidirectional uses edges into double-headed arrows. The dot layout works well for hierarchical call graphs; for larger graphs, fdp (force-directed) can produce more readable results:

pyan3 src/*.py --dot --colored --no-defines --concentrate --graphviz-layout fdp --file output.dot
fdp -Tsvg output.dot -o output.svg

For a high-level overview, add --depth 1 to collapse everything down to modules, classes, and top-level functions:

pyan3 src/*.py --dot --colored --no-defines --concentrate --depth 1 --file overview.dot

Graph depth control

Collapse the graph to a desired level of detail:

pyan3 src/ --dot --depth 0      # modules only (call-graph view, not import deps)
pyan3 src/ --dot --depth 1      # + classes and top-level functions
pyan3 src/ --dot --depth 2      # + methods
pyan3 src/ --dot --depth max    # full detail (default)

Filtering

Focus on a specific function or namespace:

pyan3 src/ --dot --function pkg.mod.MyClass.method
pyan3 src/ --dot --namespace pkg.mod

# Control traversal direction (requires --function or --namespace)
pyan3 src/ --dot --function pkg.mod.func --direction down   # callees only (what does this function call?)
pyan3 src/ --dot --function pkg.mod.func --direction up     # callers only (what calls this function?)

Call path listing

List all call paths between two functions:

pyan3 src/ --paths-from pkg.mod.caller --paths-to pkg.mod.target

Uses depth-first search (DFS); results are sorted shortest first among those found, capped by --max-paths (default 100).

GraphViz layout options

pyan3 src/ --dot --graphviz-layout fdp   # force-directed layout (also: neato, sfdp, twopi, circo)
pyan3 src/ --dot --dot-ranksep 1.5       # increase rank separation (inches)
pyan3 src/ --dot --concentrate           # merge bidirectional edges into double-headed arrows

Note on --concentrate: GraphViz's edge concentration can produce small gaps at edge split/merge points (endpoint coordinates differ by ~0.02–0.09 graph units). This is a known GraphViz precision issue, visible at high zoom in interactive viewers. The visual output is still useful — just be aware that concentrated edges may not join perfectly.

Python API

import pyan

# Generate a call graph as a DOT string
dot_source = pyan.create_callgraph(
    filenames="pkg/**/*.py",   # also accepts a directory path
    format="dot",              # also: "svg", "html", "tgf", "yed", "text"
    colored=True,
    nested_groups=True,
    draw_defines=True,
    draw_uses=True,
    depth=2,                   # 0=modules, 1=+classes, 2=+methods, None=full
    direction="both",          # "down" (callees), "up" (callers), "both"
    concentrate=True,          # merge bidirectional edges
    layout="dot",              # GraphViz layout algorithm
    ranksep="0.5",             # rank separation (inches)
)

# Find

Related Skills

View on GitHub
GitHub Stars405
CategoryDevelopment
Updated2h ago
Forks73

Languages

Python

Security Score

100/100

Audited on Mar 25, 2026

No findings