Skip to main content

License: MIT Python Versions (officially) supported Pypi status badge

Task Dependency Graph

Task Dependency Graph is a Python package that allows to model tasks and dependencies between tasks as a directed graph. It also supports visualizing the graph with dot for a graph-like view or mermaid for Gantt charts.

The package is built on networkx and under the hood the task dependency graph is just a networkx DiGraph. For visualization, it uses GraphViz via kroki (in a Docker container).

Example / How to use

Install the package from PyPI

pip install taskdependencygraph

Imagine the following scenario:

You and your partner are invited to a birthday party. You promised to bring a cake. Baking the cake and the recipe can be divided into atomic tasks, all of which have a duration. Those are the nodes of the task dependency graph (TDG).

Tasks are created like this:

import uuid
from datetime import timedelta

from taskdependencygraph.models import TaskNode

my_task = TaskNode(
    id=uuid.uuid4(),  # boilerplate only, but you need the ID to find nodes in your graph later on
    name="Shop groceries",  # human readable description
    external_id="some unique string",  # technical ID for those who don't like uuids ;)
    planned_duration=timedelta(minutes=15)  # how long it probably takes
    # You may also add an assignee, phase, tags, earliest_starttime, is_milestone, or execution_status
)

The tasks depend on each other: You cannot prepare the cake without buying the ingredients first. You cannot decorate the cake before you've made it. Which task has which mandatory predecessor tasks is defined in task dependencies. Those are the edges of our task dependency graph.

Task dependencies are created like this:

import uuid

from taskdependencygraph.models import TaskDependencyEdge, TaskNode

shopping_groceries = TaskNode(...)
mixing_flour_and_sugar = TaskNode(...)
baking_in_the_oven = TaskNode(...)

buy_ingredients_before_mixing_them = TaskDependencyEdge(
    id=uuid.uuid4(),  # boilerplate
    predecessor_task=shopping_groceries.id,
    successor_task=mixing_flour_and_sugar.id
)
mix_ingredients_before_baking_the_cake = TaskDependencyEdge(
    id=uuid.uuid4(),  # boilerplate
    predecessor_task=mixing_flour_and_sugar.id,
    successor_task=baking_in_the_oven.id
)

The graph is made out of tasks (nodes), task dependencies (edges) and a start datetime.

from datetime import datetime, UTC

from taskdependencygraph import TaskDependencyGraph
from taskdependencygraph.models import TaskNode, TaskDependencyEdge

# nodes
shopping_groceries = TaskNode(...)
mixing_flour_and_sugar = TaskNode(...)
baking_in_the_oven = TaskNode(...)

# edges
buy_ingredients_before_mixing_them = TaskDependencyEdge(...)
mix_ingredients_before_baking_the_cake = TaskDependencyEdge(...)

# graph
tdg = TaskDependencyGraph(
    task_list=[shopping_groceries, mixing_flour_and_sugar, baking_in_the_oven],
    dependency_list=[buy_ingredients_before_mixing_them, mix_ingredients_before_baking_the_cake],
    starting_time_of_run=datetime(2025, 1, 1, 12, 0, 0, tzinfo=UTC)
)

Once you have a graph, you can:

  • Validate the definition before construction — TaskDependencyGraph.validate_definition(task_list, dependency_list) checks for duplicate task/dependency IDs, duplicate external IDs, missing edge endpoints, invalid milestone durations, duplicate edge pairs, and cycles, returning a GraphDefinitionValidationResult.
  • Get the full schedule — tdg.create_schedule_report() returns a ScheduleReport with planned start/finish, critical-path flag, and total slack for every task.
  • Inspect the critical path — tdg.get_critical_path_tasks() returns the ordered list of TaskNode objects on the critical path.
  • Calculate total slack — tdg.calculate_total_slack_of_task(task_id) returns how much a task can slip without affecting the deadline.
  • Query finish times — tdg.calculate_planned_finish_time_of_task(task_id) and tdg.calculate_planned_finish_time_of_graph().
  • Assign persons to tasks and check if any person has more than one task assigned at a time.

Find a complete working example in the demo unittest. This demo test is also the basis for the following visualization examples.

Visualization with Kroki

You can visualize the dependencies either as rather simple technical graph or as Gantt chart, when you start kroki in a docker container:

# docker-compose.yaml
services:
  kroki: # see https://docs.kroki.io/kroki/setup/use-docker-or-podman/#_run_multiple_kroki_containers_together
    image: yuzutech/kroki:0.30.1
    depends_on:
      - mermaid
    environment:
      - KROKI_MERMAID_HOST=mermaid
    ports:
      - "8123:8000"
  mermaid:
    image: yuzutech/kroki-mermaid
# run
# docker-compose up -d
# and kroki is ready at localhost:8123
import asyncio

from taskdependencygraph import TaskDependencyGraph
from taskdependencygraph.plotting import KrokiClient, KrokiConfig


async def plot_a_graph() -> None:
    tdg = TaskDependencyGraph(...)  # with all nodes and edges and stuff

    config = KrokiConfig(host="http://localhost:8123")  # w/o docker, you may also use kroki.io, but it's rate limited
    kroki_client = KrokiClient(config=config)

    await kroki_client.plot_as_svg(tdg, mode="gantt")  # or mode="dot"


if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    loop.run_until_complete(plot_a_graph())

The result may look like this:

Gantt Chart (Mermaid)

A Gantt chart

The tasks marked in red mark the critical path on which delays affect the finishing time. The 🔶 are milestones which mark important moments in your project (often you want to have a group of tasks like ' Shopping' done before starting with the next step, even though there's no "real" dependency between e.g. Cake Base and buying the strawberries.) The Gantt chart is useful to get an overview of your project and to identify which tasks are crucial.

The Gantt output is customizable via MermaidGanttConfig — you can set the title, axis format, tick interval, and group tasks into sections by their phase field.

Raw Graph ("dot" engine)

The raw graph helps you to understand the tasks and dependencies setup in a not so shiny but verbose fashion.

Storing the Graph in a Database

You can store the nodes and edges on a database. We suggest to just use two tables: One for the edges, one for the nodes. You can even add trigger-based DB constraints to prevent loops in the graph which are faster than you might guess, even for hundreds of tasks.

Maintainers/ Further Development / Professional Support

This library was built for and then cut out of a mainly internal project by @hf-crings, @OLILHR, @hf-sheese and @hf-kklein, but we decided to publish it, because it might be useful to someone. This is why some things are hardcoded here and there and why some features might seem unintuitive at first glance.

We at Hochfrequenz also built a SQLAlchemy+FastAPI+htmx web application around this library in which you can plan and schedule time-critical tasks and projects in the browser. It's ready to use, but not pretty enough to publish it yet ;) Just ping us if interested.

Metadata

Release files for taskdependencygraph 0.3.0

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

Source distribution (sdist)

Source distribution for taskdependencygraph 0.3.0
File Size Uploaded
taskdependencygraph-0.3.0.tar.gz 34.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for taskdependencygraph 0.3.0
File Interpreter ABI Platform
taskdependencygraph-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 67.9 kB

Release files / taskdependencygraph-0.3.0.tar.gz

Download URL taskdependencygraph-0.3.0.tar.gz
Size 34.3 kB
Tags Source
SHA-256 checksum
How to use checksums
e97adb14901e4736ae816e61657f0c1bc88b2ab6f90952f3bcc862c6bfa98f7c
BLAKE2b-256 checksum
How to use checksums
8aa709b60159663de366892ad941b6426cfafbd56e4df3ad2e3bd9dfac2b8741
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on May 27, 2026.

Transparency log

Release files / taskdependencygraph-0.3.0-py3-none-any.whl

Download URL taskdependencygraph-0.3.0-py3-none-any.whl
Size 33.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d5c8325fc63a98a28149e6ea60eb01dd5d91aab59ce9c2651de397923803730c
BLAKE2b-256 checksum
How to use checksums
0688686f675b84ded309ead41679e0d4b0e8b9b41a4bdbdb1a9868f180eac35c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on May 27, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.0

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