Diagrams That Fit Python (Module-First, Not Class-First)

Most Python codebases are organized around modules, functions, and data pipelines — not deep class hierarchies. Drawing UML class diagrams for typical Python code over-formalizes simple structure and hides the real architecture, which lives at the module boundary, not the class boundary. This section documents three diagram types that match how Python is actually written.


1. Why UML Class Diagrams Don't Fit Python Well

UML class diagrams were designed for Java / C++ / C# codebases where:

Typical Python looks nothing like that. A FastAPI app has free-standing route functions, business logic in plain functions, dataclasses for DTOs, and maybe one ABC for a payment gateway. Drawing class boxes for that codebase invents structure that isn't really there — and worse, it obscures the structure that is there: the module boundaries.

Python's real units of organization are:


2. Which Diagram for Which Question

┌────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│                            Decision Tree — Which Diagram for Your Python Code?                             │
│                                                                                                            │
│                                        ┌─────────────────────────┐                                         │
│                                        │ What are you modeling ? │                                         │
│                                        └────────────┬────────────┘                                         │
│                                                     │                                                      │
│                 ┌───────────────────────────────────┴───────────────────────────────────┐                  │
│                 │                                   │                                   │                  │
│                 ▼                                   ▼                                   ▼                  │
│            "where code                         "what data                          "who talks              │
│             lives ?"                            flows ?"                           to whom ?"              │
│                 │                                   │                                   │                  │
│                 ▼                                   ▼                                   ▼                  │
│      ┌────────────────────┐              ┌────────────────────┐              ┌────────────────────┐        │
│      │       Module       │              │      Pipeline      │              │      Sequence      │        │
│      │     Dependency     │              │       / DAG        │              │      Diagram       │        │
│      │    (Pattern K)     │              │    (Pattern L)     │              │    (Pattern I)     │        │
│      └────────────────────┘              └────────────────────┘              └────────────────────┘        │
│                                                                                                            │
│   Asking instead: "what shape is this data ?"           →  Schema (Pattern M)                              │
│   Asking instead: "what states does this go through ?"  →  State diagram                                   │
│   Asking instead: "what user goal does this serve ?"    →  Use Case diagram                                │
│                                                                                                            │
│  Drawing UML class diagrams for procedural Python imposes object structure that is                         │
│  not really there. Use class diagrams ONLY when a real OOP hierarchy exists                                │
│  (Django Views, sklearn estimators, framework extension).                                                  │
└────────────────────────────────────────────────────────────────────────────────────────────────────────────┘

3. The Three Python-First Patterns

For a typical Python project, three diagram types cover almost everything you'd want to communicate about the code:

Diagram Question It Answers When To Draw It
Module Dependency Where does the code live? What imports what? Onboarding, refactoring, finding circular imports, enforcing layered architecture
Pipeline / DAG What happens to the data? In what order? ETL jobs, ML training, RAG systems, request handlers, anything pandas/sklearn/Airflow
Schema What shape is this data? Dataclasses, Pydantic models, ORM tables, API payloads
Sequence Who talks to whom? In what order? System integrations, microservice flows, async/await traces

4. When Class Diagrams DO Make Sense in Python

Class diagrams aren't useless in Python — they're just the wrong default. They earn their keep when:

For everything else — dataclasses, ORM models, Pydantic schemas, API payloads — use a schema diagram instead. It drops the methods section and treats the class purely as data shape, which is what Python developers actually mean when they say "this class."


5. Other Diagrams Worth Considering


Common Interview Questions:

Why are class diagrams less useful in Python than in Java?

Python's units of organization are modules and functions, not classes. Most Python code uses dataclasses for data and free-standing functions for behavior. Inheritance hierarchies are typically 1 level deep (or zero). A class diagram for procedural Python invents structure — the meaningful relationships are imports between modules, not message-passing between objects.

What's the most useful diagram for a brand-new Python project?

A module dependency diagram. It's grounded in the only thing Python forces to be explicit (import statements), it surfaces real problems (circular imports, layer violations, god modules), and it can be auto-generated from source by tools like pydeps or tach, so it doesn't drift.

When does a sequence diagram beat a pipeline diagram?

Sequence diagrams emphasize WHO is communicating; pipelines emphasize WHAT is being transformed. Use a sequence diagram when multiple systems are involved (browser, API gateway, queue, database, third-party service). Use a pipeline diagram when one process flows data through stages (read → clean → embed → store).

How do I diagram a Django app?

Three diagrams: (1) module dependency for app layout (apps directory, models / views / serializers / tasks), (2) schema diagram for the ORM models (drawn as ER), (3) sequence diagram for any interesting request flow. Skip class diagrams of the View class hierarchy — the framework is doing the work; the diagram doesn't add value.

Should I draw a class diagram for an LLM agent?

No. Draw a sequence diagram for the agent loop (model → tool call → tool result → model → final answer) and a pipeline diagram for the RAG ingestion side. The "classes" in an LLM app are mostly Pydantic schemas (use schema diagrams) and one or two thin orchestration classes that don't need their own UML.

How do I detect a god module without a diagram?

grep -rl 'from utils import' . | wc -l — if more than 50% of your modules import from one file, you have a god module. The diagram makes it visible at a glance, but the real test is the dependency count. Tools like pydeps --max-bacon=2 or tach flag this automatically.


↑ Back to Top