pydot

Build, parse, and render Graphviz DOT graphs from pure Python.

Library
PyPI
v4.0.1
1,000stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
73/100Good
Development Activity84
Maintenance40
Community80
Maturity60
Momentum28

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
70/100Good
Architecture75
Code Quality90
Innovation70
Learning Curve45

pydot is a pure-Python interface to Graphviz’s DOT graph description language. It lets you construct directed and undirected graphs programmatically — adding nodes, edges, subgraphs, and clusters as native Python objects — then render them to any format Graphviz supports (PNG, SVG, PDF, PostScript, and dozens more) by shelling out to the locally installed Graphviz binaries.

Beyond generation, pydot can also parse existing DOT files or strings back into the same object model using a pyparsing-based grammar, making round-trips between DOT source and Python objects straightforward. It integrates directly with NetworkX’s nx_pydot module for converting between NetworkX graphs and pydot graphs, and is commonly used as the rendering backend behind higher-level graph-visualization tooling.

What You Get

  • A typed object model (Dot, Graph, Subgraph, Cluster, Node, Edge) covering the full set of Graphviz graph/node/edge/cluster attributes
  • Auto-generated write_<format>() and create_<format>() methods for every Graphviz output format (PNG, SVG, PDF, PostScript, GIF, and more)
  • A pyparsing-based DOT parser (graph_from_dot_file / graph_from_dot_data) for round-tripping existing DOT source back into Python objects
  • Direct interoperability with NetworkX via its nx_pydot conversion module

Common Use Cases

  • Rendering dependency graphs, call graphs, or state machines generated from another tool’s output
  • Visualizing NetworkX graphs by converting them to pydot and rendering with Graphviz
  • Parsing and editing existing .dot files programmatically (e.g. relabeling nodes, recoloring edges) before re-rendering
  • Generating architecture or data-lineage diagrams dynamically from application data

Under The Hood

Architecture pydot has a flat, four-module layout: classes.py defines low-level container types (FrozenDict, AttributeDict, EdgeEndpoint); core.py defines the core object model (Common base class, Node, Edge, Graph, Subgraph, Cluster, Dot) plus a subprocess-based rendering pipeline (call_graphviz, Dot.create/write, and dynamically generated per-format write_*/create_* methods); dot_parser.py implements a pyparsing grammar that reconstructs those same objects from DOT text (graph_from_dot_data/graph_from_dot_file); and exceptions.py holds a small typed exception hierarchy. Data flows both ways — pydot objects serialize via to_string() to DOT syntax and are handed to the Graphviz binaries through subprocess.Popen, while the parser reverses that path from DOT source back into objects. Every class shares Common’s dict-based attribute storage (obj_dict), so that scheme is the one abstraction the whole object model depends on.

Tech Stack A pure Python 3.9+ package with a single runtime dependency, pyparsing>=3.1.0, used for grammar-based DOT parsing. Rendering delegates to the external Graphviz binaries (dot, twopi, neato, circo, fdp, sfdp) invoked via subprocess.Popen, so Graphviz itself is a required system dependency rather than a Python package. Build tooling is setuptools (>=77) through pyproject.toml with a dynamically read version attribute; dev tooling covers ruff for linting, mypy --strict for typing, pytest/pytest-cov/pytest-xdist plus tox for testing, and zest.releaser for releases. A trimmed copy of CPython 3.12’s tempfile module is vendored to backport ignore_cleanup_errors support to older Python versions. CI runs the full matrix across Python 3.9–3.15 on Ubuntu, Windows, and macOS.

Code Quality The test suite spans six files (test_api.py, test_classes.py, test_context_managers.py, test_logging.py, test_parser.py, test_pydot.py) covering the public API, parsing round-trips, context-manager behavior, and logging output, with coverage tracked via a dedicated coverage-comment CI badge. mypy runs in strict mode across the source tree, with consistent type hints, TYPE_CHECKING-gated imports, and Final/cast annotations throughout. Error handling is explicit rather than swallowed: a small typed exception hierarchy backs parser errors, and Dot.create() re-raises OSError with a clarified message when the Graphviz binary isn’t found. Style is enforced by ruff across an extensive rule set, and everything runs in CI on every push. This reads as a mature, well-governed codebase — typed, tested, linted, and cross-platform CI-gated.

API Design The public surface is small and discoverable: Dot, Graph, Subgraph, Cluster, Node, and Edge, each accepting Graphviz attributes as keyword arguments and exposing add_node/add_edge/add_subgraph alongside auto-generated get_*/set_* accessors for every valid Graphviz attribute. Getting started requires little boilerplate — construct a Dot, add nodes and edges, and call write_png() or create_svg() without ever touching the underlying subprocess call directly, or go the other way with a one-line graph_from_dot_file(). Docstrings are unusually thorough for a library this size, covering platform-specific caveats in detail. The main friction point is that format-specific methods like write_png() are generated dynamically rather than declared explicitly, which can make them less visible to IDEs and type checkers without special-casing. The overall approach — attribute-dict object model plus subprocess-shelled rendering — is the standard pattern for a Graphviz Python binding rather than a novel one, but it’s executed cleanly.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search