taskdependencygraph 0.1.0__tar.gz → 0.2.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {taskdependencygraph-0.1.0 → taskdependencygraph-0.2.1}/.github/dependabot.yml +0 -2
- {taskdependencygraph-0.1.0 → taskdependencygraph-0.2.1}/.github/workflows/codeql-analysis.yml +4 -4
- {taskdependencygraph-0.1.0 → taskdependencygraph-0.2.1}/.github/workflows/coverage.yml +5 -9
- {taskdependencygraph-0.1.0 → taskdependencygraph-0.2.1}/.github/workflows/dev_test.yml +3 -3
- {taskdependencygraph-0.1.0 → taskdependencygraph-0.2.1}/.github/workflows/formatting.yml +5 -7
- {taskdependencygraph-0.1.0 → taskdependencygraph-0.2.1}/.github/workflows/no_byte_order_mark.yml +1 -1
- {taskdependencygraph-0.1.0 → taskdependencygraph-0.2.1}/.github/workflows/packaging_test.yml +5 -9
- {taskdependencygraph-0.1.0 → taskdependencygraph-0.2.1}/.github/workflows/python-publish.yml +6 -6
- {taskdependencygraph-0.1.0 → taskdependencygraph-0.2.1}/.github/workflows/pythonlint.yml +5 -7
- {taskdependencygraph-0.1.0 → taskdependencygraph-0.2.1}/.github/workflows/unittests.yml +3 -3
- {taskdependencygraph-0.1.0 → taskdependencygraph-0.2.1}/PKG-INFO +21 -17
- {taskdependencygraph-0.1.0 → taskdependencygraph-0.2.1}/README.md +12 -9
- {taskdependencygraph-0.1.0 → taskdependencygraph-0.2.1}/pyproject.toml +10 -9
- taskdependencygraph-0.2.1/requirements.txt +60 -0
- taskdependencygraph-0.2.1/src/_taskdependencygraph_version.py +1 -0
- taskdependencygraph-0.2.1/src/taskdependencygraph/__init__.py +59 -0
- {taskdependencygraph-0.1.0 → taskdependencygraph-0.2.1}/src/taskdependencygraph/models/__init__.py +27 -9
- taskdependencygraph-0.2.1/src/taskdependencygraph/models/graph_definition_validation.py +50 -0
- taskdependencygraph-0.2.1/src/taskdependencygraph/models/mermaid_gantt_config.py +67 -0
- taskdependencygraph-0.2.1/src/taskdependencygraph/models/schedule_report.py +47 -0
- {taskdependencygraph-0.1.0 → taskdependencygraph-0.2.1}/src/taskdependencygraph/models/task_node.py +8 -2
- {taskdependencygraph-0.1.0 → taskdependencygraph-0.2.1}/src/taskdependencygraph/models/task_node_as_artificial_endnode.py +0 -1
- {taskdependencygraph-0.1.0 → taskdependencygraph-0.2.1}/src/taskdependencygraph/plotting/protocols.py +3 -1
- {taskdependencygraph-0.1.0 → taskdependencygraph-0.2.1}/src/taskdependencygraph/task_dependency_graph.py +416 -19
- {taskdependencygraph-0.1.0 → taskdependencygraph-0.2.1}/tox.ini +0 -2
- taskdependencygraph-0.1.0/.pre-commit-config.yaml +0 -24
- taskdependencygraph-0.1.0/requirements.txt +0 -54
- taskdependencygraph-0.1.0/src/_taskdependencygraph_version.py +0 -1
- taskdependencygraph-0.1.0/src/taskdependencygraph/__init__.py +0 -8
- {taskdependencygraph-0.1.0 → taskdependencygraph-0.2.1}/.github/workflows/dependabot_automerge.yml +0 -0
- {taskdependencygraph-0.1.0 → taskdependencygraph-0.2.1}/.gitignore +0 -0
- {taskdependencygraph-0.1.0 → taskdependencygraph-0.2.1}/domain-specific-terms.txt +0 -0
- {taskdependencygraph-0.1.0 → taskdependencygraph-0.2.1}/src/taskdependencygraph/models/ids.py +0 -0
- {taskdependencygraph-0.1.0 → taskdependencygraph-0.2.1}/src/taskdependencygraph/models/person.py +0 -0
- {taskdependencygraph-0.1.0 → taskdependencygraph-0.2.1}/src/taskdependencygraph/models/task_dependency_edge.py +0 -0
- {taskdependencygraph-0.1.0 → taskdependencygraph-0.2.1}/src/taskdependencygraph/models/task_dependency_update.py +0 -0
- {taskdependencygraph-0.1.0 → taskdependencygraph-0.2.1}/src/taskdependencygraph/models/task_execution_status.py +0 -0
- {taskdependencygraph-0.1.0 → taskdependencygraph-0.2.1}/src/taskdependencygraph/models/task_node_as_artificial_startnode.py +0 -0
- {taskdependencygraph-0.1.0 → taskdependencygraph-0.2.1}/src/taskdependencygraph/plotting/__init__.py +0 -0
- {taskdependencygraph-0.1.0 → taskdependencygraph-0.2.1}/src/taskdependencygraph/plotting/kroki.py +0 -0
- {taskdependencygraph-0.1.0 → taskdependencygraph-0.2.1}/src/taskdependencygraph/py.typed +0 -0
{taskdependencygraph-0.1.0 → taskdependencygraph-0.2.1}/.github/workflows/codeql-analysis.yml
RENAMED
|
@@ -38,11 +38,11 @@ jobs:
|
|
|
38
38
|
|
|
39
39
|
steps:
|
|
40
40
|
- name: Checkout repository
|
|
41
|
-
uses: actions/checkout@
|
|
41
|
+
uses: actions/checkout@v6
|
|
42
42
|
|
|
43
43
|
# Initializes the CodeQL tools for scanning.
|
|
44
44
|
- name: Initialize CodeQL
|
|
45
|
-
uses: github/codeql-action/init@
|
|
45
|
+
uses: github/codeql-action/init@v4
|
|
46
46
|
with:
|
|
47
47
|
languages: ${{ matrix.language }}
|
|
48
48
|
# If you wish to specify custom queries, you can do so here or in a config file.
|
|
@@ -53,7 +53,7 @@ jobs:
|
|
|
53
53
|
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
|
54
54
|
# If this step fails, then you should remove it and run the build manually (see below)
|
|
55
55
|
- name: Autobuild
|
|
56
|
-
uses: github/codeql-action/autobuild@
|
|
56
|
+
uses: github/codeql-action/autobuild@v4
|
|
57
57
|
|
|
58
58
|
# ℹ️ Command-line programs to run using the OS shell.
|
|
59
59
|
# 📚 https://git.io/JvXDl
|
|
@@ -67,4 +67,4 @@ jobs:
|
|
|
67
67
|
# make release
|
|
68
68
|
|
|
69
69
|
- name: Perform CodeQL Analysis
|
|
70
|
-
uses: github/codeql-action/analyze@
|
|
70
|
+
uses: github/codeql-action/analyze@v4
|
|
@@ -6,17 +6,13 @@ on:
|
|
|
6
6
|
pull_request: {}
|
|
7
7
|
jobs:
|
|
8
8
|
coverage:
|
|
9
|
-
runs-on:
|
|
10
|
-
strategy:
|
|
11
|
-
matrix:
|
|
12
|
-
python-version: ["3.13"]
|
|
13
|
-
os: [ubuntu-latest]
|
|
9
|
+
runs-on: ubuntu-latest
|
|
14
10
|
steps:
|
|
15
|
-
- uses: actions/checkout@
|
|
16
|
-
- name: Set up Python
|
|
17
|
-
uses: actions/setup-python@
|
|
11
|
+
- uses: actions/checkout@v6
|
|
12
|
+
- name: Set up Python 3.14
|
|
13
|
+
uses: actions/setup-python@v6
|
|
18
14
|
with:
|
|
19
|
-
python-version:
|
|
15
|
+
python-version: "3.14"
|
|
20
16
|
- name: Install dependencies
|
|
21
17
|
run: |
|
|
22
18
|
python -m pip install --upgrade pip
|
|
@@ -11,12 +11,12 @@ jobs:
|
|
|
11
11
|
runs-on: ${{ matrix.os }}
|
|
12
12
|
strategy:
|
|
13
13
|
matrix:
|
|
14
|
-
python-version: ["3.11", "3.12", "3.13"]
|
|
14
|
+
python-version: ["3.11", "3.12", "3.13", "3.14"]
|
|
15
15
|
os: [ubuntu-latest]
|
|
16
16
|
steps:
|
|
17
|
-
- uses: actions/checkout@
|
|
17
|
+
- uses: actions/checkout@v6
|
|
18
18
|
- name: Set up Python ${{ matrix.python-version }}
|
|
19
|
-
uses: actions/setup-python@
|
|
19
|
+
uses: actions/setup-python@v6
|
|
20
20
|
with:
|
|
21
21
|
python-version: ${{ matrix.python-version }}
|
|
22
22
|
- name: Install Dependencies
|
|
@@ -6,18 +6,16 @@ on:
|
|
|
6
6
|
pull_request: {}
|
|
7
7
|
jobs:
|
|
8
8
|
black:
|
|
9
|
-
runs-on:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
10
|
strategy:
|
|
11
11
|
matrix:
|
|
12
|
-
python-version: ["3.13"]
|
|
13
|
-
os: [ubuntu-latest]
|
|
14
12
|
tool: ["black", "isort"]
|
|
15
13
|
steps:
|
|
16
|
-
- uses: actions/checkout@
|
|
17
|
-
- name: Set up Python
|
|
18
|
-
uses: actions/setup-python@
|
|
14
|
+
- uses: actions/checkout@v6
|
|
15
|
+
- name: Set up Python 3.14
|
|
16
|
+
uses: actions/setup-python@v6
|
|
19
17
|
with:
|
|
20
|
-
python-version:
|
|
18
|
+
python-version: "3.14"
|
|
21
19
|
- name: Install dependencies
|
|
22
20
|
run: |
|
|
23
21
|
python -m pip install --upgrade pip
|
{taskdependencygraph-0.1.0 → taskdependencygraph-0.2.1}/.github/workflows/packaging_test.yml
RENAMED
|
@@ -6,17 +6,13 @@ on:
|
|
|
6
6
|
pull_request: {}
|
|
7
7
|
jobs:
|
|
8
8
|
check_packaging:
|
|
9
|
-
runs-on:
|
|
10
|
-
strategy:
|
|
11
|
-
matrix:
|
|
12
|
-
python-version: ["3.13"]
|
|
13
|
-
os: [ubuntu-latest]
|
|
9
|
+
runs-on: ubuntu-latest
|
|
14
10
|
steps:
|
|
15
|
-
- uses: actions/checkout@
|
|
16
|
-
- name: Set up Python
|
|
17
|
-
uses: actions/setup-python@
|
|
11
|
+
- uses: actions/checkout@v6
|
|
12
|
+
- name: Set up Python 3.14
|
|
13
|
+
uses: actions/setup-python@v6
|
|
18
14
|
with:
|
|
19
|
-
python-version:
|
|
15
|
+
python-version: 3.14
|
|
20
16
|
- name: Install dependencies
|
|
21
17
|
run: |
|
|
22
18
|
python -m pip install --upgrade pip
|
{taskdependencygraph-0.1.0 → taskdependencygraph-0.2.1}/.github/workflows/python-publish.yml
RENAMED
|
@@ -17,12 +17,12 @@
|
|
|
17
17
|
runs-on: ${{ matrix.os }}
|
|
18
18
|
strategy:
|
|
19
19
|
matrix:
|
|
20
|
-
python-version: ["3.
|
|
20
|
+
python-version: ["3.14"]
|
|
21
21
|
os: [ubuntu-latest]
|
|
22
22
|
steps:
|
|
23
|
-
- uses: actions/checkout@
|
|
23
|
+
- uses: actions/checkout@v6
|
|
24
24
|
- name: Set up Python ${{ matrix.python-version }}
|
|
25
|
-
uses: actions/setup-python@
|
|
25
|
+
uses: actions/setup-python@v6
|
|
26
26
|
with:
|
|
27
27
|
python-version: ${{ matrix.python-version }}
|
|
28
28
|
- name: Install tox
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
runs-on: ${{ matrix.os }}
|
|
39
39
|
strategy:
|
|
40
40
|
matrix:
|
|
41
|
-
python-version: [ "3.
|
|
41
|
+
python-version: [ "3.14" ]
|
|
42
42
|
os: [ ubuntu-latest ]
|
|
43
43
|
# Specifying a GitHub environment, # Specifying a GitHub environment, which is strongly recommended by PyPI: https://docs.pypi.org/trusted-publishers/adding-a-publisher/
|
|
44
44
|
# you have to create an environment in your repository settings and add the environment name here
|
|
@@ -48,9 +48,9 @@
|
|
|
48
48
|
id-token: write
|
|
49
49
|
needs: tests
|
|
50
50
|
steps:
|
|
51
|
-
- uses: actions/checkout@
|
|
51
|
+
- uses: actions/checkout@v6
|
|
52
52
|
- name: Set up Python ${{ matrix.python-version }}
|
|
53
|
-
uses: actions/setup-python@
|
|
53
|
+
uses: actions/setup-python@v6
|
|
54
54
|
with:
|
|
55
55
|
python-version: ${{ matrix.python-version }}
|
|
56
56
|
- name: Install dependencies
|
|
@@ -7,18 +7,16 @@ on:
|
|
|
7
7
|
jobs:
|
|
8
8
|
pylint:
|
|
9
9
|
name: Python Code Quality and Lint
|
|
10
|
-
runs-on:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
11
|
strategy:
|
|
12
12
|
matrix:
|
|
13
|
-
python-version: ["3.13"]
|
|
14
|
-
os: [ubuntu-latest]
|
|
15
13
|
linter-env: ["linting", "type_check", "spell_check"]
|
|
16
14
|
steps:
|
|
17
|
-
- uses: actions/checkout@
|
|
18
|
-
- name: Set up Python
|
|
19
|
-
uses: actions/setup-python@
|
|
15
|
+
- uses: actions/checkout@v6
|
|
16
|
+
- name: Set up Python 3.14
|
|
17
|
+
uses: actions/setup-python@v6
|
|
20
18
|
with:
|
|
21
|
-
python-version:
|
|
19
|
+
python-version: "3.14"
|
|
22
20
|
- name: Install Dependencies
|
|
23
21
|
run: |
|
|
24
22
|
python -m pip install --upgrade pip
|
|
@@ -9,12 +9,12 @@ jobs:
|
|
|
9
9
|
runs-on: ${{ matrix.os }}
|
|
10
10
|
strategy:
|
|
11
11
|
matrix:
|
|
12
|
-
python-version: ["3.11", "3.12", "3.13"]
|
|
12
|
+
python-version: ["3.11", "3.12", "3.13", "3.14"]
|
|
13
13
|
os: [ubuntu-latest]
|
|
14
14
|
steps:
|
|
15
|
-
- uses: actions/checkout@
|
|
15
|
+
- uses: actions/checkout@v6
|
|
16
16
|
- name: Set up Python ${{ matrix.python-version }}
|
|
17
|
-
uses: actions/setup-python@
|
|
17
|
+
uses: actions/setup-python@v6
|
|
18
18
|
with:
|
|
19
19
|
python-version: ${{ matrix.python-version }}
|
|
20
20
|
- name: Install Dependencies
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: taskdependencygraph
|
|
3
|
-
Version: 0.1
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: Wrapper around a NetworkX Digraph to model and visualize tasks/todos, their duration and interdependencies
|
|
5
5
|
Project-URL: Changelog, https://github.com/Hochfrequenz/task-dependency-graph/releases
|
|
6
6
|
Project-URL: Homepage, https://github.com/Hochfrequenz/task-dependency-graph
|
|
@@ -17,31 +17,32 @@ Classifier: Programming Language :: Python :: 3 :: Only
|
|
|
17
17
|
Classifier: Programming Language :: Python :: 3.11
|
|
18
18
|
Classifier: Programming Language :: Python :: 3.12
|
|
19
19
|
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
20
21
|
Requires-Python: >=3.11
|
|
21
22
|
Requires-Dist: aiohttp
|
|
22
23
|
Requires-Dist: networkx
|
|
23
24
|
Requires-Dist: pydantic-settings
|
|
24
25
|
Requires-Dist: pydantic[email]>=2
|
|
25
26
|
Provides-Extra: coverage
|
|
26
|
-
Requires-Dist: coverage==7.
|
|
27
|
+
Requires-Dist: coverage==7.9.1; extra == 'coverage'
|
|
27
28
|
Provides-Extra: dev
|
|
28
29
|
Requires-Dist: pip-tools; extra == 'dev'
|
|
29
30
|
Provides-Extra: formatting
|
|
30
|
-
Requires-Dist: black==
|
|
31
|
-
Requires-Dist: isort==
|
|
31
|
+
Requires-Dist: black==26.5.1; extra == 'formatting'
|
|
32
|
+
Requires-Dist: isort==8.0.1; extra == 'formatting'
|
|
32
33
|
Provides-Extra: linting
|
|
33
|
-
Requires-Dist: pylint==
|
|
34
|
+
Requires-Dist: pylint==4.0.5; extra == 'linting'
|
|
34
35
|
Provides-Extra: packaging
|
|
35
36
|
Requires-Dist: build==1.2.2.post1; extra == 'packaging'
|
|
36
37
|
Requires-Dist: twine==6.1.0; extra == 'packaging'
|
|
37
38
|
Provides-Extra: spell-check
|
|
38
39
|
Requires-Dist: codespell==2.4.1; extra == 'spell-check'
|
|
39
40
|
Provides-Extra: tests
|
|
40
|
-
Requires-Dist: pytest-asyncio==
|
|
41
|
-
Requires-Dist: pytest==8.
|
|
41
|
+
Requires-Dist: pytest-asyncio==1.1.0; extra == 'tests'
|
|
42
|
+
Requires-Dist: pytest==8.4.2; extra == 'tests'
|
|
42
43
|
Requires-Dist: testcontainers; extra == 'tests'
|
|
43
44
|
Provides-Extra: type-check
|
|
44
|
-
Requires-Dist: mypy==1.
|
|
45
|
+
Requires-Dist: mypy==2.1.0; extra == 'type-check'
|
|
45
46
|
Requires-Dist: types-docker; extra == 'type-check'
|
|
46
47
|
Description-Content-Type: text/markdown
|
|
47
48
|
|
|
@@ -87,9 +88,7 @@ my_task = TaskNode(
|
|
|
87
88
|
name="Shop groceries", # human readable description
|
|
88
89
|
external_id="some unique string", # technical ID for those who don't like uuids ;)
|
|
89
90
|
planned_duration=timedelta(minutes=15) # how long it probably takes
|
|
90
|
-
# You may also add an
|
|
91
|
-
# (The latter is useful, when e.g. the supermarket opens at 7am and you cannot shop groceries before,
|
|
92
|
-
# even if you were awake and have nothing else todo.)
|
|
91
|
+
# You may also add an assignee, phase, tags, earliest_starttime, is_milestone, or execution_status
|
|
93
92
|
)
|
|
94
93
|
```
|
|
95
94
|
|
|
@@ -147,12 +146,14 @@ tdg = TaskDependencyGraph(
|
|
|
147
146
|
)
|
|
148
147
|
```
|
|
149
148
|
|
|
150
|
-
|
|
149
|
+
Once you have a graph, you can:
|
|
151
150
|
|
|
152
|
-
*
|
|
153
|
-
*
|
|
154
|
-
|
|
155
|
-
*
|
|
151
|
+
* **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`.
|
|
152
|
+
* **Get the full schedule** — `tdg.create_schedule_report()` returns a `ScheduleReport` with planned start/finish, critical-path flag, and total slack for every task.
|
|
153
|
+
* **Inspect the critical path** — `tdg.get_critical_path_tasks()` returns the ordered list of `TaskNode` objects on the critical path.
|
|
154
|
+
* **Calculate total slack** — `tdg.calculate_total_slack_of_task(task_id)` returns how much a task can slip without affecting the deadline.
|
|
155
|
+
* **Query finish times** — `tdg.calculate_planned_finish_time_of_task(task_id)` and `tdg.calculate_planned_finish_time_of_graph()`.
|
|
156
|
+
* Assign persons to tasks and check if any person has more than one task assigned at a time.
|
|
156
157
|
|
|
157
158
|
Find a complete working example in [the demo unittest](unittests/test_demonstration.py).
|
|
158
159
|
This demo test is also the basis for the following visualization examples.
|
|
@@ -166,7 +167,7 @@ docker container:
|
|
|
166
167
|
# docker-compose.yaml
|
|
167
168
|
services:
|
|
168
169
|
kroki: # see https://docs.kroki.io/kroki/setup/use-docker-or-podman/#_run_multiple_kroki_containers_together
|
|
169
|
-
image: yuzutech/kroki:0.
|
|
170
|
+
image: yuzutech/kroki:0.30.1
|
|
170
171
|
depends_on:
|
|
171
172
|
- mermaid
|
|
172
173
|
environment:
|
|
@@ -213,6 +214,9 @@ Shopping' done before starting with the next step, even though there's no "real"
|
|
|
213
214
|
buying the strawberries.)
|
|
214
215
|
The Gantt chart is useful to get an overview of your project and to identify which tasks are crucial.
|
|
215
216
|
|
|
217
|
+
The Gantt output is customizable via `MermaidGanttConfig` — you can set the title, axis format, tick interval, and
|
|
218
|
+
group tasks into sections by their `phase` field.
|
|
219
|
+
|
|
216
220
|
### Raw Graph ("dot" engine)
|
|
217
221
|
|
|
218
222
|

|
|
@@ -40,9 +40,7 @@ my_task = TaskNode(
|
|
|
40
40
|
name="Shop groceries", # human readable description
|
|
41
41
|
external_id="some unique string", # technical ID for those who don't like uuids ;)
|
|
42
42
|
planned_duration=timedelta(minutes=15) # how long it probably takes
|
|
43
|
-
# You may also add an
|
|
44
|
-
# (The latter is useful, when e.g. the supermarket opens at 7am and you cannot shop groceries before,
|
|
45
|
-
# even if you were awake and have nothing else todo.)
|
|
43
|
+
# You may also add an assignee, phase, tags, earliest_starttime, is_milestone, or execution_status
|
|
46
44
|
)
|
|
47
45
|
```
|
|
48
46
|
|
|
@@ -100,12 +98,14 @@ tdg = TaskDependencyGraph(
|
|
|
100
98
|
)
|
|
101
99
|
```
|
|
102
100
|
|
|
103
|
-
|
|
101
|
+
Once you have a graph, you can:
|
|
104
102
|
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
|
|
108
|
-
*
|
|
103
|
+
* **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`.
|
|
104
|
+
* **Get the full schedule** — `tdg.create_schedule_report()` returns a `ScheduleReport` with planned start/finish, critical-path flag, and total slack for every task.
|
|
105
|
+
* **Inspect the critical path** — `tdg.get_critical_path_tasks()` returns the ordered list of `TaskNode` objects on the critical path.
|
|
106
|
+
* **Calculate total slack** — `tdg.calculate_total_slack_of_task(task_id)` returns how much a task can slip without affecting the deadline.
|
|
107
|
+
* **Query finish times** — `tdg.calculate_planned_finish_time_of_task(task_id)` and `tdg.calculate_planned_finish_time_of_graph()`.
|
|
108
|
+
* Assign persons to tasks and check if any person has more than one task assigned at a time.
|
|
109
109
|
|
|
110
110
|
Find a complete working example in [the demo unittest](unittests/test_demonstration.py).
|
|
111
111
|
This demo test is also the basis for the following visualization examples.
|
|
@@ -119,7 +119,7 @@ docker container:
|
|
|
119
119
|
# docker-compose.yaml
|
|
120
120
|
services:
|
|
121
121
|
kroki: # see https://docs.kroki.io/kroki/setup/use-docker-or-podman/#_run_multiple_kroki_containers_together
|
|
122
|
-
image: yuzutech/kroki:0.
|
|
122
|
+
image: yuzutech/kroki:0.30.1
|
|
123
123
|
depends_on:
|
|
124
124
|
- mermaid
|
|
125
125
|
environment:
|
|
@@ -166,6 +166,9 @@ Shopping' done before starting with the next step, even though there's no "real"
|
|
|
166
166
|
buying the strawberries.)
|
|
167
167
|
The Gantt chart is useful to get an overview of your project and to identify which tasks are crucial.
|
|
168
168
|
|
|
169
|
+
The Gantt output is customizable via `MermaidGanttConfig` — you can set the title, axis format, tick interval, and
|
|
170
|
+
group tasks into sections by their `phase` field.
|
|
171
|
+
|
|
169
172
|
### Raw Graph ("dot" engine)
|
|
170
173
|
|
|
171
174
|

|
|
@@ -16,6 +16,7 @@ classifiers = [
|
|
|
16
16
|
"Programming Language :: Python :: 3.11",
|
|
17
17
|
"Programming Language :: Python :: 3.12",
|
|
18
18
|
"Programming Language :: Python :: 3.13",
|
|
19
|
+
"Programming Language :: Python :: 3.14",
|
|
19
20
|
]
|
|
20
21
|
dependencies = [
|
|
21
22
|
"pydantic[email]>=2",
|
|
@@ -27,27 +28,27 @@ dynamic = ["readme", "version"]
|
|
|
27
28
|
|
|
28
29
|
[project.optional-dependencies]
|
|
29
30
|
tests = [
|
|
30
|
-
"pytest==8.
|
|
31
|
-
"pytest-asyncio==
|
|
31
|
+
"pytest==8.4.2",
|
|
32
|
+
"pytest-asyncio==1.1.0",
|
|
32
33
|
"testcontainers",
|
|
33
34
|
# "syrupy==4.8.2"
|
|
34
35
|
]
|
|
35
36
|
linting = [
|
|
36
|
-
"pylint==
|
|
37
|
+
"pylint==4.0.5"
|
|
37
38
|
]
|
|
38
39
|
type_check = [
|
|
39
|
-
"mypy==1.
|
|
40
|
+
"mypy==2.1.0",
|
|
40
41
|
"types-docker"
|
|
41
42
|
]
|
|
42
43
|
spell_check = [
|
|
43
44
|
"codespell==2.4.1"
|
|
44
45
|
]
|
|
45
46
|
coverage = [
|
|
46
|
-
"coverage==7.
|
|
47
|
+
"coverage==7.9.1"
|
|
47
48
|
]
|
|
48
49
|
formatting = [
|
|
49
|
-
"black==
|
|
50
|
-
"isort==
|
|
50
|
+
"black==26.5.1",
|
|
51
|
+
"isort==8.0.1"
|
|
51
52
|
]
|
|
52
53
|
packaging = [
|
|
53
54
|
"build==1.2.2.post1",
|
|
@@ -64,7 +65,7 @@ Homepage = "https://github.com/Hochfrequenz/task-dependency-graph"
|
|
|
64
65
|
|
|
65
66
|
[tool.black]
|
|
66
67
|
line-length = 120
|
|
67
|
-
target_version = ["py311", "py312", "py313"]
|
|
68
|
+
target_version = ["py311", "py312", "py313", "py314"]
|
|
68
69
|
|
|
69
70
|
[tool.isort]
|
|
70
71
|
line_length = 120
|
|
@@ -109,4 +110,4 @@ sources = ["src"]
|
|
|
109
110
|
|
|
110
111
|
[tool.pytest.ini_options]
|
|
111
112
|
asyncio_mode = "auto"
|
|
112
|
-
# markers = ["snapshot: mark a test as a snapshot test"]
|
|
113
|
+
# markers = ["snapshot: mark a test as a snapshot test"]
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
#
|
|
2
|
+
# This file is autogenerated by pip-compile with Python 3.12
|
|
3
|
+
# by the following command:
|
|
4
|
+
#
|
|
5
|
+
# pip-compile pyproject.toml
|
|
6
|
+
#
|
|
7
|
+
aiohappyeyeballs==2.6.2
|
|
8
|
+
# via aiohttp
|
|
9
|
+
aiohttp==3.13.5
|
|
10
|
+
# via taskdependencygraph (pyproject.toml)
|
|
11
|
+
aiosignal==1.4.0
|
|
12
|
+
# via aiohttp
|
|
13
|
+
annotated-types==0.7.0
|
|
14
|
+
# via pydantic
|
|
15
|
+
attrs==26.1.0
|
|
16
|
+
# via aiohttp
|
|
17
|
+
dnspython==2.8.0
|
|
18
|
+
# via email-validator
|
|
19
|
+
email-validator==2.3.0
|
|
20
|
+
# via pydantic
|
|
21
|
+
frozenlist==1.8.0
|
|
22
|
+
# via
|
|
23
|
+
# aiohttp
|
|
24
|
+
# aiosignal
|
|
25
|
+
idna==3.16
|
|
26
|
+
# via
|
|
27
|
+
# email-validator
|
|
28
|
+
# yarl
|
|
29
|
+
multidict==6.7.1
|
|
30
|
+
# via
|
|
31
|
+
# aiohttp
|
|
32
|
+
# yarl
|
|
33
|
+
networkx==3.6.1
|
|
34
|
+
# via taskdependencygraph (pyproject.toml)
|
|
35
|
+
propcache==0.5.2
|
|
36
|
+
# via
|
|
37
|
+
# aiohttp
|
|
38
|
+
# yarl
|
|
39
|
+
pydantic[email]==2.13.4
|
|
40
|
+
# via
|
|
41
|
+
# pydantic-settings
|
|
42
|
+
# taskdependencygraph (pyproject.toml)
|
|
43
|
+
pydantic-core==2.46.4
|
|
44
|
+
# via pydantic
|
|
45
|
+
pydantic-settings==2.14.1
|
|
46
|
+
# via taskdependencygraph (pyproject.toml)
|
|
47
|
+
python-dotenv==1.2.2
|
|
48
|
+
# via pydantic-settings
|
|
49
|
+
typing-extensions==4.15.0
|
|
50
|
+
# via
|
|
51
|
+
# aiosignal
|
|
52
|
+
# pydantic
|
|
53
|
+
# pydantic-core
|
|
54
|
+
# typing-inspection
|
|
55
|
+
typing-inspection==0.4.2
|
|
56
|
+
# via
|
|
57
|
+
# pydantic
|
|
58
|
+
# pydantic-settings
|
|
59
|
+
yarl==1.24.2
|
|
60
|
+
# via aiohttp
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
version = "0.2.1"
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""
|
|
2
|
+
taskdependencygraph is a library to model tasks and dependencies between tasks in a networkx DiGraph
|
|
3
|
+
and give estimates when which task will be done
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
# pylint: disable=duplicate-code
|
|
7
|
+
# The __all__ list here intentionally mirrors models/__init__.py — re-exporting is the purpose of this file.
|
|
8
|
+
|
|
9
|
+
from .models import (
|
|
10
|
+
ID_OF_ARTIFICIAL_ENDNODE,
|
|
11
|
+
ID_OF_ARTIFICIAL_STARTNODE,
|
|
12
|
+
AddEdgeToGraphPreviewResponse,
|
|
13
|
+
AddNodeToGraphPreviewResponse,
|
|
14
|
+
GraphDefinitionValidationFinding,
|
|
15
|
+
GraphDefinitionValidationResult,
|
|
16
|
+
MermaidGanttConfig,
|
|
17
|
+
Person,
|
|
18
|
+
PersonId,
|
|
19
|
+
RunGroupId,
|
|
20
|
+
RunGroupPersonRelationId,
|
|
21
|
+
RunId,
|
|
22
|
+
ScheduleEntry,
|
|
23
|
+
ScheduleReport,
|
|
24
|
+
TaskDependencyEdge,
|
|
25
|
+
TaskDependencyId,
|
|
26
|
+
TaskExecutionStatus,
|
|
27
|
+
TaskId,
|
|
28
|
+
TaskNode,
|
|
29
|
+
ValidationCode,
|
|
30
|
+
task_node_as_artificial_endnode,
|
|
31
|
+
task_node_as_artificial_startnode,
|
|
32
|
+
)
|
|
33
|
+
from .task_dependency_graph import TaskDependencyGraph
|
|
34
|
+
|
|
35
|
+
__all__ = [
|
|
36
|
+
"AddEdgeToGraphPreviewResponse",
|
|
37
|
+
"AddNodeToGraphPreviewResponse",
|
|
38
|
+
"GraphDefinitionValidationFinding",
|
|
39
|
+
"GraphDefinitionValidationResult",
|
|
40
|
+
"ID_OF_ARTIFICIAL_ENDNODE",
|
|
41
|
+
"ID_OF_ARTIFICIAL_STARTNODE",
|
|
42
|
+
"MermaidGanttConfig",
|
|
43
|
+
"Person",
|
|
44
|
+
"PersonId",
|
|
45
|
+
"RunGroupId",
|
|
46
|
+
"RunGroupPersonRelationId",
|
|
47
|
+
"RunId",
|
|
48
|
+
"ScheduleEntry",
|
|
49
|
+
"ScheduleReport",
|
|
50
|
+
"TaskDependencyEdge",
|
|
51
|
+
"TaskDependencyId",
|
|
52
|
+
"TaskDependencyGraph",
|
|
53
|
+
"TaskExecutionStatus",
|
|
54
|
+
"TaskId",
|
|
55
|
+
"TaskNode",
|
|
56
|
+
"ValidationCode",
|
|
57
|
+
"task_node_as_artificial_endnode",
|
|
58
|
+
"task_node_as_artificial_startnode",
|
|
59
|
+
]
|
{taskdependencygraph-0.1.0 → taskdependencygraph-0.2.1}/src/taskdependencygraph/models/__init__.py
RENAMED
|
@@ -1,24 +1,42 @@
|
|
|
1
1
|
"""models are python objects which we use to model tasks, dependencies and the graph they form"""
|
|
2
2
|
|
|
3
|
+
from .graph_definition_validation import (
|
|
4
|
+
GraphDefinitionValidationFinding,
|
|
5
|
+
GraphDefinitionValidationResult,
|
|
6
|
+
ValidationCode,
|
|
7
|
+
)
|
|
3
8
|
from .ids import PersonId, RunGroupId, RunGroupPersonRelationId, RunId, TaskDependencyId, TaskId
|
|
9
|
+
from .mermaid_gantt_config import MermaidGanttConfig
|
|
4
10
|
from .person import Person
|
|
11
|
+
from .schedule_report import ScheduleEntry, ScheduleReport
|
|
5
12
|
from .task_dependency_edge import TaskDependencyEdge
|
|
13
|
+
from .task_dependency_update import AddEdgeToGraphPreviewResponse, AddNodeToGraphPreviewResponse
|
|
6
14
|
from .task_execution_status import TaskExecutionStatus
|
|
7
15
|
from .task_node import TaskNode
|
|
8
|
-
from .task_node_as_artificial_endnode import ID_OF_ARTIFICIAL_ENDNODE
|
|
9
|
-
from .task_node_as_artificial_startnode import ID_OF_ARTIFICIAL_STARTNODE
|
|
16
|
+
from .task_node_as_artificial_endnode import ID_OF_ARTIFICIAL_ENDNODE, task_node_as_artificial_endnode
|
|
17
|
+
from .task_node_as_artificial_startnode import ID_OF_ARTIFICIAL_STARTNODE, task_node_as_artificial_startnode
|
|
10
18
|
|
|
11
19
|
__all__ = [
|
|
20
|
+
"AddEdgeToGraphPreviewResponse",
|
|
21
|
+
"AddNodeToGraphPreviewResponse",
|
|
22
|
+
"GraphDefinitionValidationFinding",
|
|
23
|
+
"GraphDefinitionValidationResult",
|
|
24
|
+
"ID_OF_ARTIFICIAL_ENDNODE",
|
|
25
|
+
"ID_OF_ARTIFICIAL_STARTNODE",
|
|
26
|
+
"MermaidGanttConfig",
|
|
12
27
|
"Person",
|
|
13
|
-
"
|
|
28
|
+
"PersonId",
|
|
14
29
|
"RunGroupId",
|
|
15
30
|
"RunGroupPersonRelationId",
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"TaskNode",
|
|
31
|
+
"RunId",
|
|
32
|
+
"ScheduleEntry",
|
|
33
|
+
"ScheduleReport",
|
|
20
34
|
"TaskDependencyEdge",
|
|
35
|
+
"TaskDependencyId",
|
|
21
36
|
"TaskExecutionStatus",
|
|
22
|
-
"
|
|
23
|
-
"
|
|
37
|
+
"TaskId",
|
|
38
|
+
"TaskNode",
|
|
39
|
+
"ValidationCode",
|
|
40
|
+
"task_node_as_artificial_endnode",
|
|
41
|
+
"task_node_as_artificial_startnode",
|
|
24
42
|
]
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Graph definition validation models.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from enum import Enum
|
|
6
|
+
|
|
7
|
+
from pydantic import BaseModel, ConfigDict
|
|
8
|
+
|
|
9
|
+
from taskdependencygraph.models.ids import TaskDependencyId, TaskId
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class ValidationCode(str, Enum):
|
|
13
|
+
"""Stable codes identifying the kind of graph definition problem found."""
|
|
14
|
+
|
|
15
|
+
DUPLICATE_TASK_ID = "DUPLICATE_TASK_ID"
|
|
16
|
+
DUPLICATE_EXTERNAL_ID = "DUPLICATE_EXTERNAL_ID"
|
|
17
|
+
MISSING_EDGE_ENDPOINT = "MISSING_EDGE_ENDPOINT"
|
|
18
|
+
DUPLICATE_DEPENDENCY_ID = "DUPLICATE_DEPENDENCY_ID"
|
|
19
|
+
DUPLICATE_EDGE_PAIR = "DUPLICATE_EDGE_PAIR"
|
|
20
|
+
CYCLE = "CYCLE"
|
|
21
|
+
INVALID_MILESTONE_DURATION = "INVALID_MILESTONE_DURATION"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class GraphDefinitionValidationFinding(BaseModel):
|
|
25
|
+
"""A single validation problem found in a graph definition."""
|
|
26
|
+
|
|
27
|
+
model_config = ConfigDict(frozen=True)
|
|
28
|
+
|
|
29
|
+
code: ValidationCode
|
|
30
|
+
message: str
|
|
31
|
+
task_id: TaskId | None = None
|
|
32
|
+
"""The task ID involved in this finding.
|
|
33
|
+
For MISSING_EDGE_ENDPOINT this may be an ID that does not exist in the task list."""
|
|
34
|
+
dependency_id: TaskDependencyId | None = None
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class GraphDefinitionValidationResult(BaseModel):
|
|
38
|
+
"""The aggregated result of validating a raw task/dependency list before graph construction."""
|
|
39
|
+
|
|
40
|
+
model_config = ConfigDict(frozen=True)
|
|
41
|
+
|
|
42
|
+
is_valid: bool
|
|
43
|
+
findings: tuple[GraphDefinitionValidationFinding, ...]
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
__all__ = [
|
|
47
|
+
"GraphDefinitionValidationFinding",
|
|
48
|
+
"GraphDefinitionValidationResult",
|
|
49
|
+
"ValidationCode",
|
|
50
|
+
]
|