11"""Implement some capabilities to deal with the DAG."""
22import itertools
3- import pprint
3+ from pathlib import Path
44from typing import Dict
55from typing import Generator
66from typing import Iterable
77from typing import List
88
99import attr
1010import networkx as nx
11+ from _pytask .console import format_strings_as_flat_tree
12+ from _pytask .console import TASK_ICON
1113from _pytask .mark import get_specific_markers_from_task
1214from _pytask .nodes import MetaTask
15+ from _pytask .nodes import reduce_node_name
1316
1417
1518def descending_tasks (task_name : str , dag : nx .DiGraph ) -> Generator [str , None , None ]:
@@ -52,14 +55,17 @@ class TopologicalSorter:
5255 _nodes_out = attr .ib (factory = set )
5356
5457 @classmethod
55- def from_dag (cls , dag : nx .DiGraph ) -> "TopologicalSorter" :
58+ def from_dag (cls , dag : nx .DiGraph , paths : List [Path ] = None ) -> "TopologicalSorter" :
59+ if paths is None :
60+ paths = []
61+
5662 if not dag .is_directed ():
5763 raise ValueError ("Only directed graphs have a topological order." )
5864
5965 tasks = [
6066 dag .nodes [node ]["task" ] for node in dag .nodes if "task" in dag .nodes [node ]
6167 ]
62- priorities = _extract_priorities_from_tasks (tasks )
68+ priorities = _extract_priorities_from_tasks (tasks , paths )
6369
6470 task_names = {task .name for task in tasks }
6571 task_dict = {name : nx .ancestors (dag , name ) & task_names for name in task_names }
@@ -118,7 +124,9 @@ def static_order(self) -> Generator[str, None, None]:
118124 self .done (new_task )
119125
120126
121- def _extract_priorities_from_tasks (tasks : List [MetaTask ]) -> Dict [str , int ]:
127+ def _extract_priorities_from_tasks (
128+ tasks : List [MetaTask ], paths : List [Path ]
129+ ) -> Dict [str , int ]:
122130 """Extract priorities from tasks.
123131
124132 Priorities are set via the ``pytask.mark.try_first`` and ``pytask.mark.try_last``
@@ -138,10 +146,19 @@ def _extract_priorities_from_tasks(tasks: List[MetaTask]) -> Dict[str, int]:
138146 tasks_w_mixed_priorities = [
139147 name for name , p in priorities .items () if p ["try_first" ] and p ["try_last" ]
140148 ]
149+
141150 if tasks_w_mixed_priorities :
151+ name_to_task = {task .name : task for task in tasks }
152+ reduced_names = [
153+ reduce_node_name (name_to_task [name ], paths )
154+ for name in tasks_w_mixed_priorities
155+ ]
156+ text = format_strings_as_flat_tree (
157+ reduced_names , "Tasks with mixed priorities" , TASK_ICON
158+ )
142159 raise ValueError (
143160 "'try_first' and 'try_last' cannot be applied on the same task. See the "
144- f"following tasks for errors:\n \n { pprint . pformat ( tasks_w_mixed_priorities ) } "
161+ f"following tasks for errors:\n \n { text } "
145162 )
146163
147164 # Recode to numeric values for sorting.
0 commit comments