Skip to main content

Static analysis CLI for Python import graphs and dependency summaries

Project description

NetImport: Python Project Architecture Analyzer via Import Graphs

NetImport is a static analysis CLI for Python projects. It scans source files, parses import statements, resolves those imports into project, standard-library, external, or unresolved dependencies, and then presents the result as either a dependency graph or a deterministic console summary.

It is intended for architecture inspection, refactoring support, and CI-friendly dependency review. The current release is positioned as a beta-stage developer tool: the core workflows are implemented and tested, while known static-analysis limitations are documented explicitly.

Quick Start

Install NetImport and run it against a project directory:

pip install netimport
netimport example --show-console-summary --no-show-graph

If you are working from this repository locally:

poetry install
poetry run netimport example --show-console-summary --no-show-graph

Remove --no-show-graph if you want to open the graph visualization instead of running in summary-only mode.

Core Features

  • Import Analysis: Recursively scans the specified project directory for Python files and parses their import statements.
  • Dependency Graph Construction: Creates a directed graph where nodes represent project modules/packages, as well as external and standard libraries. Edges depict the imports between them.
  • Graph Visualization: Supports an interactive Bokeh view and a static Matplotlib view with explicit backend/layout compatibility.
  • Console Summary: Prints a deterministic text report with project-level counts and coupling tables.
  • Configuration via CLI and TOML files: Supports CLI overrides plus config from [tool.netimport] in pyproject.toml, .netimport.toml, or an explicit --config TOML file.
  • Dependency Type Identification: Distinguishes imports of internal project modules, Python standard libraries, and external third-party dependencies.

Why Use NetImport?

  • Understand Project Structure: Gain a clear visual overview of how different parts of your application are interconnected. This is especially useful for new team members or when working with legacy code.
  • Assess Coupling: Identify modules that are highly dependent on each other. High coupling can make code harder to change, test, and reuse.
  • Gauge Cohesion (Indirectly): While directly calculating cohesion from imports alone is difficult, the graph can provide insights into how logically grouped functionalities are within a module by observing its dependencies.
  • Aid Refactoring: Use the graph as a map during refactoring to understand which parts of the system will be affected by changes.
  • Architectural Oversight: Helps in maintaining a clean and understandable architecture by making dependencies explicit.

Current Support Contract

NetImport currently supports:

  • Static analysis of Python source trees based on AST-parsed import statements.
  • Deterministic console summaries for headless runs and CI-oriented inspection.
  • Explicit visualizer backend/layout combinations documented in the CLI and README.
  • Configuration from [tool.netimport] in pyproject.toml, .netimport.toml, explicit --config files, and CLI overrides.

Installation

pip install netimport

or

poetry add netimport

Usage

NetImport can be used from the command line and is suitable for integration into CI/CD pipelines.

Command Line Interface

netimport [OPTIONS] <PROJECT_PATH>

Current CLI Options

PROJECT_PATH

Path to the root directory of the Python project to analyze.

--layout [constrained|spring|circular|shell|planar_layout]

Choose a layout name for the selected graph backend. If omitted, NetImport uses the backend default.

--config FILE

Load an explicit TOML config file and apply it after project config has been loaded from the analyzed project. The file may either contain top-level NetImport keys or a [tool.netimport] section.

--show-graph [bokeh|mpl]

Select the visualization backend. Current default is bokeh.

Supported backend/layout combinations:

  • bokeh: constrained (default)
  • mpl: spring (default), circular, shell, planar_layout

Unsupported combinations are rejected with a clear CLI error instead of silently falling back.

--no-show-graph

Disable graph visualization even if a graph backend is configured. This is useful for CI, terminals, or summary-only runs.

--show-console-summary

Print a textual dependency report with tables for:

  • overall graph counts
  • project coupling metrics
  • most/least coupled project files
  • most depended-on project files
  • most dependent project files
  • external dependencies
  • unresolved imports

--summary-format [text|json]

Choose the output format for --show-console-summary.

--fail-on-violation

Exit with code 1 when configured policy violations are found. This is intended for CI usage together with summary output.

  • text keeps the current human-readable table output
  • json emits a deterministic machine-readable report for CI and automation

--ignored-dir TEXT

Ignore a directory name during project file discovery. Can be passed multiple times.

--ignored-file TEXT

Ignore a file name during project file discovery. Can be passed multiple times.

--ignored-node TEXT

Ignore a graph node by label or id. Can be passed multiple times.

--ignore-stdlib / --include-stdlib

Override whether standard library modules should be excluded.

--ignore-external-lib / --include-external-lib

Override whether external libraries should be excluded.

Examples

Below are the supported launch modes with a short explanation of what each mode is for.

Default interactive mode

Use this when you want the standard interactive graph view with folder grouping and node dragging.

poetry run netimport example

This is equivalent to --show-graph bokeh --layout constrained.

Explicit Bokeh mode

Use this when you want to call the default interactive mode explicitly in scripts, docs, or manual checks.

poetry run netimport example --show-graph bokeh --layout constrained

This opens the Bokeh visualizer with the constrained layout.

Matplotlib spring mode

Use this as the most universal static Matplotlib layout. It is the safest choice when you want a readable static graph for general-purpose inspection.

poetry run netimport example --show-graph mpl --layout spring

Matplotlib circular mode

Use this when you want a simple ring-like layout that is easy to scan on small or medium graphs.

poetry run netimport example --show-graph mpl --layout circular

Matplotlib shell mode

Use this when you want a layered visual structure with nodes arranged in shells.

poetry run netimport example --show-graph mpl --layout shell

Matplotlib planar mode

Use this only when a planar-style view is useful for the current graph. For dense or non-planar dependency graphs, this mode may be less practical than spring.

poetry run netimport example --show-graph mpl --layout planar_layout

Graph plus console summary

Use this when you want both the graph visualization and the textual dependency report in the same run.

poetry run netimport example --show-console-summary

Summary-only mode

Use this in CI, SSH sessions, terminals without GUI support, or when you only need the textual report.

poetry run netimport example --show-console-summary --no-show-graph

JSON summary mode

Use this in CI or scripts when you want a stable machine-readable dependency report.

poetry run netimport example --show-console-summary --summary-format json --no-show-graph

Explicit config file

Use this when you want to keep a reusable analysis profile outside the analyzed project root, or when CI should point NetImport at a dedicated config file.

poetry run netimport example --config ci/netimport.toml --show-console-summary --no-show-graph

Example summary output:

Dependency Graph Summary
========================
+--------------------------+-------+
| Metric                   | Value |
+--------------------------+-------+
| Nodes                    | 14    |
| Edges                    | 18    |
| Project files            | 11    |
| Standard library modules | 3     |
| External libraries       | 0     |
| Unresolved imports       | 0     |
+--------------------------+-------+

Project Coupling Metrics
========================
+------------------------+------+--------+-----+-----+
| Metric                 | Avg  | Median | Min | Max |
+------------------------+------+--------+-----+-----+
| Project files analyzed | 11   | -      | -   | -   |
| Incoming degree        | 0.91 | 1.00   | 0   | 3   |
| Outgoing degree        | 1.64 | 1.00   | 0   | 5   |
| Total degree           | 2.55 | 2.00   | 0   | 5   |
+------------------------+------+--------+-----+-----+

Configuration

NetImport reads configuration from the analyzed project directory, not from the caller's current working directory.

Supported config files:

  • [tool.netimport] in pyproject.toml
  • .netimport.toml
  • explicit TOML file passed via --config

Precedence:

  1. built-in defaults
  2. pyproject.toml
  3. .netimport.toml
  4. explicit --config file
  5. CLI options

For collection options (ignored_dirs, ignored_files, ignored_nodes), later file-based config replaces earlier file-based values, and CLI values are added on top at the final step. For boolean options (ignore_stdlib, ignore_external_lib), later config sources replace earlier ones, and explicit CLI flags override file config values.

Supported keys:

  • ignored_dirs
  • ignored_files
  • ignore_stdlib
  • ignore_external_lib
  • ignored_nodes
  • fail_on_unresolved_imports
  • forbidden_external_libs

pyproject.toml example:

[tool.netimport]
ignored_dirs = ["venv", ".venv", "tests", "docs", "__pycache__", "node_modules", "migrations"]
ignored_files = ["setup.py", "manage.py"]
ignore_stdlib = true
ignore_external_lib = true
ignored_nodes = []
fail_on_unresolved_imports = true
forbidden_external_libs = ["requests"]

.netimport.toml example:

ignored_dirs = ["venv", ".venv"]
ignored_files = ["setup.py"]
ignore_stdlib = false
ignore_external_lib = false
ignored_nodes = []
fail_on_unresolved_imports = false
forbidden_external_libs = []

Explicit --config example using top-level keys:

ignored_dirs = ["generated"]
ignored_files = ["bootstrap.py"]
ignore_stdlib = true
ignore_external_lib = false
ignored_nodes = ["requests"]
fail_on_unresolved_imports = true
forbidden_external_libs = ["requests"]

Explicit --config can also point to a pyproject.toml-style file:

[tool.netimport]
ignored_dirs = ["generated"]
ignore_stdlib = true

Current Limitations

NetImport is intentionally conservative about unsupported cases. Today that means:

  • It is a static analyzer, so runtime imports, plugin loading, and sys.path mutations are not modeled.
  • Namespace packages are not part of the supported resolver contract.
  • from ... import * is handled conservatively and may remain partial when exports are dynamic.
  • Visualization support is limited to the documented backend/layout combinations instead of silently guessing unsupported modes.

Roadmap

The items below are future enhancements, not part of the current support contract.

  • Architectural Metrics Calculation:
    • Count of incoming/outgoing dependencies for each module (Afferent/Efferent Couplings).
    • Calculation of Instability (I) metric.
    • (Further research needed for A) Calculation of Abstractness (A) and Distance from Main Sequence (D) metrics, potentially with user-assisted annotation for abstract components.
  • Defining Layers and Rule Checking: Ability to define architectural layers and validate rules between them (e.g., via a configuration file).
  • Advanced Visualization:
    • Interactive HTML reports (e.g., using pyvis or bokeh).
    • Highlighting specific nodes or paths on the graph.
    • Grouping nodes by package or defined layer.
  • Plugin for popular IDEs (VSCode, PyCharm).
  • CI/CD Integration: Output results in CI-friendly formats (e.g., JUnit XML), allow setting metric thresholds.
  • Improved Import Resolution:
    • Better handling of all for more accurate analysis of from ... import *.
    • More precise import resolution considering sys.path modifications and namespace packages.

Contributing

Contributions are welcome to make NetImport better! If you'd like to help, please check out CONTRIBUTING.md for instructions on setting up your development environment, code style, and the process for submitting Pull Requests.

Key areas for contribution:

  • Implementing new features from the Roadmap.
  • Improving the existing codebase (refactoring, optimization).
  • Writing tests.
  • Enhancing documentation.
  • Bug fixing.

Feel free to open Issues to discuss new ideas or problems.

License

This project is licensed under the MIT License. See LICENSE.txt for the full text.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

netimport-0.1.0.tar.gz (32.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

netimport-0.1.0-py3-none-any.whl (33.7 kB view details)

Uploaded Python 3

File details

Details for the file netimport-0.1.0.tar.gz.

File metadata

  • Download URL: netimport-0.1.0.tar.gz
  • Upload date:
  • Size: 32.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.3.1 CPython/3.13.7 Darwin/24.6.0

File hashes

Hashes for netimport-0.1.0.tar.gz
Algorithm Hash digest
SHA256 ba1dfc2fea76f44dd125a598fe1bfb45373a0340629bb3f231da0691e804dc02
MD5 de049d132bbae3e96a8920b2202935e1
BLAKE2b-256 45212855cc896d24ce009e3bfd243dbf277ac12f4994d9d321ed8ed551d873fc

See more details on using hashes here.

File details

Details for the file netimport-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: netimport-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 33.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.3.1 CPython/3.13.7 Darwin/24.6.0

File hashes

Hashes for netimport-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 4a92ce1a3da6abb7776a3a134e2082d713b427fbe88a589d5bfbc3c23555fdbe
MD5 7ba28c92d118dda0cf3e9d7265bedb17
BLAKE2b-256 00e365765f2d78cb2bbca0562b999fa145ab297f50680df6012fabc7d0740df5

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page