How code-review-graph Parses and Analyzes Jupyter Notebooks: A Technical Deep Dive

code-review-graph treats Jupyter notebooks as first-class source files by mapping .ipynb extensions to a specialized parser that extracts JSON cells, dispatches language-specific analyzers per cell, and unifies the results into a single graph structure.

The code-review-graph repository provides a token-efficient AI code review system that understands complex codebases, including Jupyter notebooks. When analyzing how code-review-graph parses and analyzes Jupyter notebooks, the implementation reveals a sophisticated three-stage pipeline that handles mixed-language cells and integrates notebook entities seamlessly into the knowledge graph.

File-Type Detection: Mapping .ipynb to the Notebook Parser

The parsing workflow begins with extension-based file identification. When the parser encounters a path ending with .ipynb, the internal extension map resolves it to the logical language identifier "notebook".

In code_review_graph/parser.py at line 754, the extension mapping logic recognizes Jupyter notebooks and routes them through the specialized notebook parsing pipeline rather than treating them as plain text or JSON configuration files. This detection triggers the multi-stage analysis that treats the notebook as a composite source file containing potentially heterogeneous code cells.

JSON Extraction and Cell-Level Language Dispatch

Once identified as a notebook, the file is loaded as a JSON document. The parser iterates through the notebook's cell array, inspecting each cell's cell_type and optional metadata.language property (or shebang declarations in the source) to determine the programming language.

The dispatch mechanism routes cells to appropriate Tree-sitter parsers:

  • Python cells are processed by the standard Python Tree-sitter parser
  • R cells are dispatched to the R parser
  • SQL cells are analyzed using the SQL grammar

This per-cell dispatch architecture enables a single notebook to contain mixed-language code while still producing a unified abstract syntax tree (AST) representation. The system maintains language context across cell boundaries, ensuring that imports defined in early Python cells are recognized in subsequent cells within the same notebook.

AST-to-Graph Conversion for Notebooks

For every cell that yields a parse tree, the generic AST walker extracts function, class, import, and call nodes. These extracted entities are attached to a File node that represents the notebook itself, creating relationships that answer queries such as "what functions are defined in analysis.ipynb?" or "which notebooks import a given module?".

The resulting graph structure contains:

  • Nodes: Functions, classes, imports, and calls identified within notebook cells
  • Edges: Definition relationships linking code entities to the parent notebook file

This approach ensures that notebooks participate fully in the codebase graph alongside traditional .py or .R files, enabling cross-file analysis that spans both regular source files and interactive notebooks.

Incremental Parsing and Performance Optimization

The notebook parsing pipeline supports incremental updates to minimize reprocessing costs. The system calculates a SHA-256 hash of each notebook file's contents and compares it against the stored hash in the graph database.

Only notebooks whose hash has changed since the last analysis are re-parsed, keeping the computational cost comparable to ordinary source files. This optimization is crucial for large data science repositories containing numerous exploratory notebooks that change infrequently compared to core library code.

Practical Usage: CLI and Programmatic Examples

Command-Line Interface

Build the graph for a project containing notebooks using the CLI:

code-review-graph build          # discovers *.ipynb files and parses them

code-review-graph query "functions in analysis.ipynb"

Python API Integration

Parse notebook files programmatically and extract specific entities:

from pathlib import Path
from code_review_graph.parser import Parser

parser = Parser()
nodes, edges = parser.parse_path(Path("analysis.ipynb"))

# Example: list all function names extracted from the notebook

func_names = [n["name"] for n in nodes if n["type"] == "function"]
print(func_names)

Query the built graph for notebook-specific symbols:

from code_review_graph.graph import Graph

g = Graph()
g.build()                                   # loads the persisted SQLite graph

functions = g.search_nodes(
    type="function",
    source_file="analysis.ipynb"
)
for fn in functions:
    print(fn["name"], fn["language"])

The implementation is validated by the test suite in tests/test_notebook.py, which verifies language detection, empty-notebook handling, and proper extraction of symbols from sample notebooks containing mixed-language cells.

Summary

  • Unified treatment: Jupyter notebooks are mapped to the "notebook" language type in code_review_graph/parser.py (line 754) and processed as composite source files
  • Multi-language support: Individual cells are dispatched to appropriate parsers (Python, R, SQL) based on metadata or shebang detection
  • Graph integration: Extracted functions, classes, and imports attach to File nodes representing the notebook, enabling unified codebase queries
  • Incremental processing: SHA-256 hashing ensures only modified notebooks are re-parsed, maintaining performance parity with standard source files
  • Comprehensive testing: The tests/test_notebook.py suite validates detection accuracy and entity extraction across diverse notebook formats

Frequently Asked Questions

Can code-review-graph handle notebooks with multiple programming languages?

Yes. The parser inspects each cell's metadata.language field or shebang declarations to dispatch cells to the appropriate Tree-sitter grammar. A single notebook can contain Python, R, and SQL cells simultaneously, with each cell parsed by its respective language analyzer while contributing to a unified graph structure.

How does the system track changes to Jupyter notebooks for incremental updates?

The system computes a SHA-256 hash of each notebook file's contents during the build process. When code-review-graph build runs subsequently, it compares the current hash against the stored value in the SQLite graph database. Only notebooks with modified hashes undergo re-parsing, significantly reducing processing time for large repositories.

What types of code entities are extracted from notebook cells?

The AST walker extracts function definitions, class definitions, import statements, and call expressions from each parseable cell. These entities become nodes in the knowledge graph with edges linking them to the parent notebook file, enabling queries that treat notebook content equivalently to traditional source files.

Where can I find test coverage for notebook parsing functionality?

Comprehensive test coverage resides in tests/test_notebook.py, which validates extension detection, empty notebook handling, multi-language cell dispatch, and correct symbol extraction. These tests ensure that notebooks containing various magics, markdown cells, and mixed languages parse correctly without disrupting the graph construction process.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →