Skip to content

Commit e50d251

Browse files
committed
refactor.
1 parent 73dab52 commit e50d251

File tree

6 files changed

+59
-65
lines changed

6 files changed

+59
-65
lines changed

src/_pytask/collect.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -597,7 +597,9 @@ def pytask_collect_log(
597597
"""Log collection."""
598598
session.collection_end = time.time()
599599

600-
console.print(f"Collected {len(tasks)} task{'' if len(tasks) == 1 else 's'}.")
600+
console.print(
601+
f"Collected {len(tasks)} task{'' if len(tasks) == 1 else 's'}.", highlight=False
602+
)
601603

602604
failed_reports = [r for r in reports if r.outcome == CollectionOutcome.FAIL]
603605
if failed_reports:

src/_pytask/execute.py

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -105,11 +105,7 @@ def pytask_execute_task_protocol(session: Session, task: PTask) -> ExecutionRepo
105105
"""Follow the protocol to execute each task."""
106106
# Initialize explanation for this task if in explain mode
107107
if session.config.get("explain", False):
108-
task._explanation = TaskExplanation( # type: ignore[attr-defined]
109-
task_name=task.name,
110-
would_execute=False,
111-
reasons=[],
112-
)
108+
task.attributes["explanation"] = TaskExplanation(reasons=[])
113109

114110
session.hook.pytask_execute_task_log_start(session=session, task=task)
115111
try:
@@ -212,9 +208,8 @@ def pytask_execute_task_setup(session: Session, task: PTask) -> None: # noqa: C
212208
needs_to_be_executed = True
213209

214210
# Update explanation on task if in explain mode
215-
if session.config["explain"] and hasattr(task, "_explanation"):
216-
task._explanation.would_execute = needs_to_be_executed
217-
task._explanation.reasons = change_reasons
211+
if session.config["explain"] and "explanation" in task.attributes:
212+
task.attributes["explanation"].reasons = change_reasons
218213

219214
if not needs_to_be_executed:
220215
collect_provisional_products(session, task)
@@ -308,7 +303,6 @@ def pytask_execute_task_process_report(
308303
309304
"""
310305
task = report.task
311-
explain_mode = session.config.get("explain", False)
312306

313307
if report.outcome == TaskOutcome.SUCCESS:
314308
update_states_in_database(session, task.signature)
@@ -342,10 +336,6 @@ def pytask_execute_task_process_report(
342336
if report.exc_info and isinstance(report.exc_info[1], Exit): # pragma: no cover
343337
session.should_stop = True
344338

345-
# Update explanation with outcome if in explain mode
346-
if explain_mode and hasattr(task, "_explanation"):
347-
task._explanation.outcome = report.outcome
348-
349339
return True
350340

351341

src/_pytask/explain.py

Lines changed: 52 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -56,29 +56,26 @@ def format(self, verbose: int = 1) -> str: # noqa: PLR0911
5656
class TaskExplanation:
5757
"""Represents the explanation for why a task needs to be executed."""
5858

59-
task_name: str
60-
would_execute: bool
61-
outcome: TaskOutcome | None = None
6259
reasons: list[ChangeReason] = field(factory=list)
6360

64-
def format(self, verbose: int = 1) -> str:
61+
def format(self, task_name: str, outcome: TaskOutcome, verbose: int = 1) -> str:
6562
"""Format the task explanation as a string."""
6663
lines = []
6764

68-
if self.outcome == TaskOutcome.SKIP_UNCHANGED:
69-
lines.append(f"{self.task_name}")
65+
if outcome == TaskOutcome.SKIP_UNCHANGED:
66+
lines.append(f"{task_name}")
7067
lines.append(" ✓ No changes detected")
71-
elif self.outcome == TaskOutcome.PERSISTENCE:
72-
lines.append(f"{self.task_name}")
68+
elif outcome == TaskOutcome.PERSISTENCE:
69+
lines.append(f"{task_name}")
7370
lines.append(" • Persisted (products exist, changes ignored)")
74-
elif self.outcome == TaskOutcome.SKIP:
75-
lines.append(f"{self.task_name}")
71+
elif outcome == TaskOutcome.SKIP:
72+
lines.append(f"{task_name}")
7673
lines.append(" • Skipped by marker")
7774
elif not self.reasons:
78-
lines.append(f"{self.task_name}")
75+
lines.append(f"{task_name}")
7976
lines.append(" ✓ No changes detected")
8077
else:
81-
lines.append(f"{self.task_name}")
78+
lines.append(f"{task_name}")
8279
lines.extend(reason.format(verbose) for reason in self.reasons)
8380

8481
return "\n".join(lines)
@@ -116,55 +113,73 @@ def pytask_execute_log_end(session: Session, reports: list[ExecutionReport]) ->
116113
console.rule(Text("Explanation", style="bold blue"), style="bold blue")
117114
console.print()
118115

119-
# Collect all explanations
120-
explanations = [
121-
report.task._explanation
122-
for report in reports
123-
if hasattr(report.task, "_explanation")
116+
# Collect all reports with explanations
117+
reports_with_explanations = [
118+
report for report in reports if "explanation" in report.task.attributes
124119
]
125120

126-
if not explanations:
121+
if not reports_with_explanations:
127122
console.print("No tasks require execution - everything is up to date.")
128123
return
129124

130125
# Group by outcome
131-
would_execute = [e for e in explanations if e.would_execute]
126+
would_execute = [
127+
r
128+
for r in reports_with_explanations
129+
if r.outcome == TaskOutcome.WOULD_BE_EXECUTED
130+
]
132131
skipped = [
133-
e
134-
for e in explanations
135-
if not e.would_execute and e.outcome != TaskOutcome.SKIP_UNCHANGED
132+
r
133+
for r in reports_with_explanations
134+
if r.outcome in (TaskOutcome.SKIP, TaskOutcome.SKIP_PREVIOUS_FAILED)
135+
]
136+
unchanged = [
137+
r for r in reports_with_explanations if r.outcome == TaskOutcome.SKIP_UNCHANGED
136138
]
137-
unchanged = [e for e in explanations if e.outcome == TaskOutcome.SKIP_UNCHANGED]
138139

139140
verbose = session.config.get("verbose", 1)
140141

141142
if would_execute:
142-
# WOULD_BE_EXECUTED has style "success" in TaskOutcome
143-
console.print(
143+
console.rule(
144144
Text(
145-
"Tasks that would be executed:",
145+
"─── Tasks that would be executed",
146146
style=TaskOutcome.WOULD_BE_EXECUTED.style,
147147
),
148+
align="left",
149+
style=TaskOutcome.WOULD_BE_EXECUTED.style,
148150
)
149151
console.print()
150-
for exp in would_execute:
151-
console.print(exp.format(verbose))
152+
for report in would_execute:
153+
explanation = report.task.attributes["explanation"]
154+
console.print(explanation.format(report.task.name, report.outcome, verbose))
152155
console.print()
153156

154157
if skipped:
155-
# SKIP has style "skipped" in TaskOutcome
156-
console.print(Text("Skipped tasks:", style=TaskOutcome.SKIP.style))
158+
console.rule(
159+
Text("─── Skipped tasks", style=TaskOutcome.SKIP.style),
160+
align="left",
161+
style=TaskOutcome.SKIP.style,
162+
)
157163
console.print()
158-
for exp in skipped:
159-
console.print(exp.format(verbose))
164+
for report in skipped:
165+
explanation = report.task.attributes["explanation"]
166+
console.print(explanation.format(report.task.name, report.outcome, verbose))
160167
console.print()
161168

162169
if unchanged and verbose >= 2: # noqa: PLR2004
163-
# SKIP_UNCHANGED has style "success" in TaskOutcome
164-
console.print(
165-
Text("Tasks with no changes:", style=TaskOutcome.SKIP_UNCHANGED.style)
170+
console.rule(
171+
Text("─── Tasks with no changes", style=TaskOutcome.SKIP_UNCHANGED.style),
172+
align="left",
173+
style=TaskOutcome.SKIP_UNCHANGED.style,
166174
)
167175
console.print()
168-
for exp in unchanged:
169-
console.print(exp.format(verbose))
176+
for report in unchanged:
177+
explanation = report.task.attributes["explanation"]
178+
console.print(explanation.format(report.task.name, report.outcome, verbose))
170179
console.print()
180+
181+
elif unchanged and verbose == 1:
182+
console.print(
183+
f"{len(unchanged)} task(s) with no changes (use -vv to show details)",
184+
highlight=False,
185+
)

src/_pytask/persist.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,6 @@ def pytask_execute_task_setup(session: Session, task: PTask) -> None:
4040
dependencies and before the same hook implementation for skipping tasks.
4141
4242
"""
43-
explain_mode = session.config.get("explain", False)
44-
4543
if has_mark(task, "persist"):
4644
all_states = [
4745
(
@@ -65,8 +63,6 @@ def pytask_execute_task_setup(session: Session, task: PTask) -> None:
6563
)
6664
if any_node_changed:
6765
collect_provisional_products(session, task)
68-
if explain_mode and hasattr(task, "_explanation"):
69-
task._explanation.outcome = TaskOutcome.PERSISTENCE
7066
raise Persisted
7167

7268

src/_pytask/skipping.py

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -49,21 +49,15 @@ def pytask_parse_config(config: dict[str, Any]) -> None:
4949
@hookimpl
5050
def pytask_execute_task_setup(session: Session, task: PTask) -> None:
5151
"""Take a short-cut for skipped tasks during setup with an exception."""
52-
explain_mode = session.config.get("explain", False)
53-
5452
is_unchanged = has_mark(task, "skip_unchanged") and not has_mark(
5553
task, "would_be_executed"
5654
)
5755
if is_unchanged and not session.config["force"]:
5856
collect_provisional_products(session, task)
59-
if explain_mode and hasattr(task, "_explanation"):
60-
task._explanation.outcome = TaskOutcome.SKIP_UNCHANGED
6157
raise SkippedUnchanged
6258

6359
is_skipped = has_mark(task, "skip")
6460
if is_skipped:
65-
if explain_mode and hasattr(task, "_explanation"):
66-
task._explanation.outcome = TaskOutcome.SKIP
6761
raise Skipped
6862

6963
skipif_marks = get_marks(task, "skipif")
@@ -72,8 +66,6 @@ def pytask_execute_task_setup(session: Session, task: PTask) -> None:
7266
message = "\n".join(arg[1] for arg in marker_args if arg[0])
7367
should_skip = any(arg[0] for arg in marker_args)
7468
if should_skip:
75-
if explain_mode and hasattr(task, "_explanation"):
76-
task._explanation.outcome = TaskOutcome.SKIP
7769
raise Skipped(message)
7870

7971
ancestor_failed_marks = get_marks(task, "skip_ancestor_failed")
@@ -82,8 +74,6 @@ def pytask_execute_task_setup(session: Session, task: PTask) -> None:
8274
skip_ancestor_failed(*mark.args, **mark.kwargs)
8375
for mark in ancestor_failed_marks
8476
)
85-
if explain_mode and hasattr(task, "_explanation"):
86-
task._explanation.outcome = TaskOutcome.SKIP_PREVIOUS_FAILED
8777
raise SkippedAncestorFailed(message)
8878

8979

tests/test_explain.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,7 @@ def task_example(produces=Path("out.txt")):
266266
or "unchanged" in result.output.lower()
267267
or "0 " in result.output
268268
)
269+
assert "1 task(s) with no changes (use -vv to show details)" in result.output
269270

270271

271272
def test_explain_with_dry_run(runner, tmp_path):

0 commit comments

Comments
 (0)