{"id":26152211,"url":"https://github.com/hochfrequenz/task-dependency-graph","last_synced_at":"2025-04-14T05:33:42.090Z","repository":{"id":280494510,"uuid":"938053307","full_name":"Hochfrequenz/task-dependency-graph","owner":"Hochfrequenz","description":"python package to model an visualize dependencies between tasks that depend on each other in a directed networkx graph and each have duration","archived":false,"fork":false,"pushed_at":"2025-04-07T17:48:16.000Z","size":48,"stargazers_count":0,"open_issues_count":5,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-04-07T18:42:27.563Z","etag":null,"topics":["directed-graph","kroki","networkx","python","tasks"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Hochfrequenz.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2025-02-24T10:50:20.000Z","updated_at":"2025-04-07T17:41:48.000Z","dependencies_parsed_at":null,"dependency_job_id":"5daf97d7-3b90-4f5c-9ec9-d0ff9c7f4c3c","html_url":"https://github.com/Hochfrequenz/task-dependency-graph","commit_stats":null,"previous_names":["hochfrequenz/task-dependency-graph"],"tags_count":1,"template":false,"template_full_name":"Hochfrequenz/python_template_repository","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Hochfrequenz%2Ftask-dependency-graph","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Hochfrequenz%2Ftask-dependency-graph/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Hochfrequenz%2Ftask-dependency-graph/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Hochfrequenz%2Ftask-dependency-graph/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Hochfrequenz","download_url":"https://codeload.github.com/Hochfrequenz/task-dependency-graph/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248827635,"owners_count":21167913,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["directed-graph","kroki","networkx","python","tasks"],"created_at":"2025-03-11T06:59:01.123Z","updated_at":"2025-04-14T05:33:42.084Z","avatar_url":"https://github.com/Hochfrequenz.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)\n![Python Versions (officially) supported](https://img.shields.io/pypi/pyversions/taskdependencygraph.svg)\n![Pypi status badge](https://img.shields.io/pypi/v/taskdependencygraph)\n\n# Task Dependency Graph\n\nTask Dependency Graph is a Python package that allows to model tasks and dependencies between tasks as a directed graph.\nIt also supports visualizing the graph with [dot](https://graphviz.org/docs/layouts/dot/) for a graph-like view\nor [mermaid](https://mermaid.js.org/) for Gantt charts.\n\nThe package is built on [networkx](https://networkx.org/) and under the hood the task dependency graph is just a\nnetworkx [DiGraph](https://networkx.org/documentation/stable/reference/classes/digraph.html).\nFor visualization, it uses GraphViz via [kroki](https://kroki.io/) (in a Docker container).\n\n## Example / How to use\n\nInstall the package from [PyPI](https://pypi.org/project/taskdependencygraph/)\n\n```bash\npip install taskdependencygraph\n```\n\nImagine the following scenario:\n\nYou and your partner are invited to a birthday party.\nYou promised to bring a cake.\nBaking the cake and the recipe can be divided into atomic tasks, all of which have a duration.\nThose are the **nodes** of the task dependency graph (TDG).\n\nTasks are created like this:\n\n```python\nimport uuid\nfrom datetime import timedelta\n\nfrom taskdependencygraph.models import TaskNode\n\nmy_task = TaskNode(\n    id=uuid.uuid4(),  # boilerplate only, but you need the ID to find nodes in your graph later on\n    name=\"Shop groceries\",  # human readable description\n    external_id=\"some unique string\",  # technical ID for those who don't like uuids ;)\n    planned_duration=timedelta(minutes=15)  # how long it probably takes\n    # You may also add an assignees or an earliest_possible_start\n    # (The latter is useful, when e.g. the supermarket opens at 7am and you cannot shop groceries before,\n    # even if you were awake and have nothing else todo.)\n)\n```\n\nThe tasks depend on each other:\nYou cannot prepare the cake without buying the ingredients first.\nYou cannot decorate the cake before you've made it.\nWhich task has which mandatory predecessor tasks is defined in task dependencies.\nThose are the **edges** of our task dependency graph.\n\nTask dependencies are created like this:\n\n```python\nimport uuid\n\nfrom taskdependencygraph.models import TaskDependencyEdge, TaskNode\n\nshopping_groceries = TaskNode(...)\nmixing_flour_and_sugar = TaskNode(...)\nbaking_in_the_oven = TaskNode(...)\n\nbuy_ingredients_before_mixing_them = TaskDependencyEdge(\n    id=uuid.uuid4(),  # boilerplate\n    predecessor_task=shopping_groceries.id,\n    successor_task=mixing_flour_and_sugar.id\n)\nmix_ingredients_before_baking_the_cake = TaskDependencyEdge(\n    id=uuid.uuid4(),  # boilerplate\n    predecessor_task=mixing_flour_and_sugar.id,\n    successor_task=baking_in_the_oven.id\n)\n```\n\nThe graph is made out of tasks (nodes), task dependencies (edges) and a start datetime.\n\n```python\nfrom datetime import datetime, UTC\n\nfrom taskdependencygraph import TaskDependencyGraph\nfrom taskdependencygraph.models import TaskNode, TaskDependencyEdge\n\n# nodes\nshopping_groceries = TaskNode(...)\nmixing_flour_and_sugar = TaskNode(...)\nbaking_in_the_oven = TaskNode(...)\n\n# edges\nbuy_ingredients_before_mixing_them = TaskDependencyEdge(...)\nmix_ingredients_before_baking_the_cake = TaskDependencyEdge(...)\n\n# graph\ntdg = TaskDependencyGraph(\n    task_list=[shopping_groceries, mixing_flour_and_sugar, baking_in_the_oven],\n    dependency_list=[buy_ingredients_before_mixing_them, mix_ingredients_before_baking_the_cake],\n    starting_time_of_run=datetime(2025, 1, 1, 12, 0, 0, tzinfo=UTC)\n)\n```\n\nNow you can\n\n* calculate at which time which task is scheduled to start depending on which predecessors it has,\n* find out which tasks are 'critical' in sense that if they're delayed, then the finishing time of the last node is also\n  delayed,\n* assign persons to tasks and check if any person has more than one task assigned at a time.\n\nFind a complete working example in [the demo unittest](unittests/test_demonstration.py).\nThis demo test is also the basis for the following visualization examples.\n\n## Visualization with Kroki\n\nYou can visualize the dependencies either as rather simple technical graph or as Gantt chart, when you start kroki in a\ndocker container:\n\n```yaml\n# docker-compose.yaml\nservices:\n  kroki: # see https://docs.kroki.io/kroki/setup/use-docker-or-podman/#_run_multiple_kroki_containers_together\n    image: yuzutech/kroki:0.24.1\n    depends_on:\n      - mermaid\n    environment:\n      - KROKI_MERMAID_HOST=mermaid\n    ports:\n      - \"8123:8000\"\n  mermaid:\n    image: yuzutech/kroki-mermaid\n# run\n# docker-compose up -d\n# and kroki is ready at localhost:8123\n```\n\n```python\nimport asyncio\n\nfrom taskdependencygraph import TaskDependencyGraph\nfrom taskdependencygraph.plotting import KrokiClient, KrokiConfig\n\n\nasync def plot_a_graph() -\u003e None:\n    tdg = TaskDependencyGraph(...)  # with all nodes and edges and stuff\n\n    config = KrokiConfig(host=\"http://localhost:8123\")  # w/o docker, you may also use kroki.io, but it's rate limited\n    kroki_client = KrokiClient(config=config)\n\n    await kroki_client.plot_as_svg(tdg, mode=\"gantt\")  # or mode=\"dot\"\n\n\nif __name__ == '__main__':\n    loop = asyncio.get_event_loop()\n    loop.run_until_complete(plot_a_graph())\n```\n\nThe result may look like this:\n\n### Gantt Chart (Mermaid)\n\n![A Gantt chart](unittests/baking_a_cake_gantt.svg)\n\nThe tasks marked in red mark the critical path on which delays affect the finishing time.\nThe 🔶 are milestones which mark important moments in your project (often you want to have a group of tasks like '\nShopping' done before starting with the next step, even though there's no \"real\" dependency between e.g. Cake Base and\nbuying the strawberries.)\nThe Gantt chart is useful to get an overview of your project and to identify which tasks are crucial.\n\n### Raw Graph (\"dot\" engine)\n\n![](unittests/baking_a_cake_dot.svg)\n\nThe raw graph helps you to understand the tasks and dependencies setup in a not so shiny but verbose fashion.\n\n## Storing the Graph in a Database\nYou can store the nodes and edges on a database.\nWe suggest to just use two tables: One for the edges, one for the nodes.\nYou can even add trigger-based [DB constraints to prevent loops in the graph](https://gist.github.com/hf-kklein/49f6d05bd29ca850e33f5ccff3e66469) which are faster than you might guess, even for hundreds of tasks.\n\n## Maintainers/ Further Development / Professional Support\nThis library was built for and then cut out of a mainly internal project by [@hf-crings](https://github.com/hf-crings), [@OLILHR](https://github.com/OLILHR), [@hf-sheese](https://github.com/hf-sheese) and [@hf-kklein](https://github.com/hf-kklein), but we decided to publish it, because it might be useful to someone.\nThis is why some things are hardcoded here and there and why some features might seem unintuitive at first glance.\n\nWe 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.\nIt's ready to use, but not pretty enough to publish it yet ;)\nJust ping us if interested.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhochfrequenz%2Ftask-dependency-graph","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhochfrequenz%2Ftask-dependency-graph","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhochfrequenz%2Ftask-dependency-graph/lists"}