Skip to main content

cgg — Python bindings

Offline, deterministic call graphs for 44 languages, in-process.

import cgg

g = cgg.analyze("./src")
print(g.to_mermaid())

No network calls, no language servers, no build artifacts required. The analysis is the same Rust pipeline the cgg command-line tool runs, in the same order, so the two cannot disagree — there is a parity test that compares this module's JSON output against the binary's on the same tree.

Install

pip install cgg-callgraphgenerator
import cgg

The distribution is cgg-callgraphgenerator; the import is cgg. PyPI's cgg belongs to an unrelated GGUF tool, so the short name was not available. Python separates these two names routinely — pip install pillow gives you import PIL.

One caveat, because the other package also installs a top-level cgg module: do not install both into the same environment. Both write to site-packages/cgg/, pip will not stop you, and whichever lands second overwrites the first. If you already have pip install cgg (the GGUF tool), use a separate virtualenv.

The extension is built against the stable ABI (abi3-py39), so a single wheel per platform covers every CPython ≥ 3.9 — no per-version builds.

Five prebuilt wheels, ~10 MB each, so pip install needs no compiler on any of them:

Wheel Covers
manylinux_2_17_x86_64 x86-64 Linux (glibc ≥ 2.17)
manylinux_2_28_aarch64 arm64 Linux (glibc ≥ 2.28)
macosx_10_12_x86_64 Intel macOS
macosx_11_0_arm64 Apple-silicon macOS
win_amd64 x86-64 Windows

An sdist ships too, so pip install still succeeds off that list — musl Linux (Alpine) and Windows on arm64 are the ones that reach for it. There pip builds from source, which needs a Rust toolchain (≥ 1.85) and takes a few minutes.

Usage

import cgg

# Whole tree.
g = cgg.analyze("./src")

# A neighbourhood around what you care about.
g = cgg.analyze("./src", filter=[r"handle_request$"], hops=2)

# Several trees, one graph.
g = cgg.analyze(["./api", "./worker"], lang=["python", "go"])

g.to_mermaid()        # str — what agents read; byte-identical to `cgg -t mermaid`
g.to_json()           # str — `cgg -t json`, bar the per-run timings it embeds
g.to_dot()            # str — Graphviz
g.to_graphml()        # str — Gephi / yEd / networkx
g.to_dict()           # dict — the escape hatch

len(g)                # callable count
g.callables           # tuple[Callable, ...]
g.edges               # tuple[Edge, ...]
g.files               # tuple[File, ...]
g.metrics             # run counters
g.notices             # what the CLI would print to stderr
g.jobs                # worker threads the run actually used

g.callable("mypkg.mod.func")     # Callable | None
g.callers_of("mypkg.mod.func")   # list[Callable]
g.callees_of("mypkg.mod.func")   # list[Callable]

Finding code nothing calls

g = cgg.analyze("./src", dead_code=True, dead_code_confidence="high")
paths = {f.id: f.path for f in g.files}
for c in g.callables:
    if c.unreferenced:
        print(f"{c.unreferenced:6} {c.qualified_name}  {paths[c.file]}:{c.start_line}")

BEST EFFORT. Every finding is a hypothesis. It means cgg could not find a caller, not that none exists — reflection, FFI, a framework cgg has no rules for, and dynamic dispatch all produce callers it cannot see.

Filtering by trust

Every edge carries how it was established and how much cgg trusts it, so you can narrow to what you are willing to rely on:

solid = [e for e in g.edges if e.confidence == "high" and e.via == "direct"]

Two things worth knowing

Renderers never build Python objects. to_mermaid() and friends render straight from the Rust graph; g.callables constructs one Python object per callable, once, then caches. Measured on cgg's own crates/ (2,019 callables): to_mermaid() produces 180 KB in 1.5 ms, the first .callables access costs 0.84 ms, and every access after it costs 0.2 µs. Both are small here and both scale with the graph, so on a repository an order of magnitude larger the attribute path is what you would notice. Reach for the renderer when a string is what you want.

Concurrent analyze() calls actually run concurrently. The GIL is released (py.detach) and there is no internal lock, so a thread pool scales. N analyses of crates/cgg-lang/src/plugins from a ThreadPoolExecutor(N), against one analysis alone (56 ms) — medians of four repetitions, 32-core host, jobs at its default of 8:

threads wall vs. one analysis
1 55 ms 0.97x
2 65 ms 1.15x
4 76 ms 1.34x
8 88 ms 1.57x

Four analyses for 1.34x the wall clock of one; eight for 1.57x. Absolute numbers are machine-specific and each analysis is already internally parallel — regenerate them rather than trusting them.

Earlier builds would have had to take a process-wide lock for the whole of analyze, because extraction read two process-global switches (DEADCODE_SIGNALS and EXTRA_REGISTRAR_VERBS) that a second concurrent call would corrupt. Those now travel in a per-run cgg_lang::ExtractCtx, so there is no lock and no shared cell. Raising jobs on one call still works and is simpler if you only have one tree to analyze.

Not in this release

--why-live proofs, the --write-roots baseline and the audit event stream are reachable from the Rust API but have no keyword and no Graph attribute here. Use the CLI for those.

The framework-coverage table is not missing — it arrives rendered, as one of the strings in g.notices, naming both what cgg recognised and what it saw without rules. What is missing is a structured object; parse the notice or use cgg --framework-coverage if you need fields.

Building from source

scripts/build-python.sh          # from the repository root

Needs cargo (Rust ≥ 1.85), uv and git — the script checks for all three up front and stops if one is missing.

cargo build compiles the .so, but only maturin can make it importable — it writes the wheel metadata and puts the library where Python will find it. That is all build-python.sh does, plus provisioning an interpreter, since abi3-py39 rules out anything older than 3.9 and a system python3 often is.

The crate is an ordinary workspace member. It builds without a Python interpreter present at all: abi3 fixes the ABI at compile time and extension-module means libpython is never linked, so Py_* resolves at load time from whichever interpreter imports the module.

License

Apache-2.0 OR MIT.

Release files for cgg-callgraphgenerator 0.8.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for cgg-callgraphgenerator 0.8.1
File Size Uploaded
cgg_callgraphgenerator-0.8.1.tar.gz 651.8 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for cgg-callgraphgenerator 0.8.1
File
cgg_callgraphgenerator-0.8.1-cp39-abi3-win_amd64.whl CPython 3.9 abi3 Windows x86-64 Details
cgg_callgraphgenerator-0.8.1-cp39-abi3-manylinux_2_28_aarch64.whl CPython 3.9 abi3 Linux glibc 2.28+ ARM64 Details
cgg_callgraphgenerator-0.8.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.9 abi3 Linux glibc 2.17+ x86-64 Details
cgg_callgraphgenerator-0.8.1-cp39-abi3-macosx_11_0_arm64.whl CPython 3.9 abi3 macOS 11.0+ ARM64 Details
cgg_callgraphgenerator-0.8.1-cp39-abi3-macosx_10_12_x86_64.whl CPython 3.9 abi3 macOS 10.12+ x86-64 Details

Total release size: 52.7 MB

Release files / cgg_callgraphgenerator-0.8.1.tar.gz

Download URL cgg_callgraphgenerator-0.8.1.tar.gz
Size 651.8 kB
Tags Source
SHA-256 checksum
How to use checksums
2d28fd732bb28358c6220e70bef3812cece07a83490b1a96f6e128b14d96d44f
BLAKE2b-256 checksum
How to use checksums
5595fbb5fd52a7f2f7368b7f41ca113bffecce82359b4ea55e20bfb56415e0fa
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / cgg_callgraphgenerator-0.8.1-cp39-abi3-win_amd64.whl

Download URL cgg_callgraphgenerator-0.8.1-cp39-abi3-win_amd64.whl
Size 10.3 MB
Tags CPython 3.9 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
37e513d83e946308d4c827b4ddcc6fe113668df54025db3e7b0ce485c8812b65
BLAKE2b-256 checksum
How to use checksums
ee5ef9916e46dc21df8f69bd1c4001ee33c84f8e6955db25ebc8e1c2b90d6085
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / cgg_callgraphgenerator-0.8.1-cp39-abi3-manylinux_2_28_aarch64.whl

Download URL cgg_callgraphgenerator-0.8.1-cp39-abi3-manylinux_2_28_aarch64.whl
Size 10.2 MB
Tags CPython 3.9 Linux glibc 2.28+ ARM64 abi3
SHA-256 checksum
How to use checksums
5fa607fb03e232e600d97febcdb033e75035af2fa1001e23ec3300d7d8fa5ff1
BLAKE2b-256 checksum
How to use checksums
36469bc47f8e07b4710de34a5618d6bef56b635390211184be108d4bbb4b4b91
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / cgg_callgraphgenerator-0.8.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL cgg_callgraphgenerator-0.8.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 10.4 MB
Tags CPython 3.9 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
2b5a542461d1e24f9eac35ae15e96242562a721c8075994db859dfe84656fb7b
BLAKE2b-256 checksum
How to use checksums
8519a0c24884626d6abf9f088793a5b1de3d8b771c09ab960ce147c8fcd21ea3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / cgg_callgraphgenerator-0.8.1-cp39-abi3-macosx_11_0_arm64.whl

Download URL cgg_callgraphgenerator-0.8.1-cp39-abi3-macosx_11_0_arm64.whl
Size 10.8 MB
Tags CPython 3.9 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
79340db66b7e63e02e6b14d16cf80381f015058374acafdc6a9723cb68ba3a1b
BLAKE2b-256 checksum
How to use checksums
94fcbe48d812344d18c966b567b2b96120b6ad7aa7e4df01d53ea8f249bde39f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / cgg_callgraphgenerator-0.8.1-cp39-abi3-macosx_10_12_x86_64.whl

Download URL cgg_callgraphgenerator-0.8.1-cp39-abi3-macosx_10_12_x86_64.whl
Size 10.3 MB
Tags CPython 3.9 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
dcfd7d0c8c35d1aea0b1e5f64bf317024b4a879ce3ee07c81b4c326f62e27c7d
BLAKE2b-256 checksum
How to use checksums
4cbf53ddb6a8a5ed04665cf157e4c5c7b3c2af8e37108dfdbac621c4b3a90ee6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release history Release notifications | RSS feed

0.10.0

6 release files

0.9.1

6 release files

0.9.0

6 release files

0.8.5

6 release files

0.8.4

6 release files

0.8.3

6 release files

0.8.2

6 release files

This release

0.8.1 This release

6 release files

0.8.0

6 release files

0.7.0

6 release files

0.6.7

6 release files

0.6.6

6 release files

0.6.5

6 release files

0.6.4

6 release files

0.6.3

2 release files

0.6.2

1 release file

0.6.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page