Skip to content

Commit 7d0ad18

Browse files
committed
Add a counter under the execution table to show completed tasks.
1 parent 6e65106 commit 7d0ad18

File tree

3 files changed

+46
-7
lines changed

3 files changed

+46
-7
lines changed

docs/source/changes.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ releases are available on [PyPI](https://pypi.org/project/pytask) and
3434
- {pull}`245` adds choices on the command line to the help pages as metavars and show
3535
defaults.
3636
- {pull}`246` formalizes choices for {class}`click.Choice` to {class}`enum.Enum`.
37+
- {pull}`248` adds a counter at the bottom of the execution table to show how many tasks
38+
have been processed.
3739

3840
## 0.1.9 - 2022-02-23
3941

src/_pytask/live.py

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from typing import Dict
66
from typing import Generator
77
from typing import List
8+
from typing import Union
89

910
import attr
1011
import click
@@ -16,9 +17,11 @@
1617
from _pytask.outcomes import TaskOutcome
1718
from _pytask.report import CollectionReport
1819
from _pytask.report import ExecutionReport
20+
from _pytask.session import Session
1921
from _pytask.shared import get_first_non_none_value
2022
from rich.live import Live
2123
from rich.status import Status
24+
from rich.style import Style
2225
from rich.table import Table
2326
from rich.text import Text
2427

@@ -83,10 +86,16 @@ def pytask_post_parse(config: dict[str, Any]) -> None:
8386
config["verbose"],
8487
config["editor_url_scheme"],
8588
)
86-
config["pm"].register(live_execution)
89+
config["pm"].register(live_execution, "live_execution")
8790

8891
live_collection = LiveCollection(live_manager)
89-
config["pm"].register(live_collection)
92+
config["pm"].register(live_collection, "live_collection")
93+
94+
95+
@hookimpl(tryfirst=True)
96+
def pytask_execute_build(session: Session) -> None:
97+
live_execution = session.config["pm"].get_plugin("live_execution")
98+
live_execution._n_tasks = len(session.tasks)
9099

91100

92101
@attr.s(eq=False)
@@ -148,6 +157,7 @@ class LiveExecution:
148157
_editor_url_scheme = attr.ib(type=str)
149158
_running_tasks = attr.ib(factory=dict, type=Dict[str, Task])
150159
_reports = attr.ib(factory=list, type=List[Dict[str, Any]])
160+
_n_tasks = attr.ib(default="x", type=Union[int, str])
151161

152162
@hookimpl(hookwrapper=True)
153163
def pytask_execute_build(self) -> Generator[None, None, None]:
@@ -156,7 +166,9 @@ def pytask_execute_build(self) -> Generator[None, None, None]:
156166
self._live_manager.start()
157167
yield
158168
self._live_manager.stop(transient=True)
159-
table = self._generate_table(reduce_table=False, sort_table=True)
169+
table = self._generate_table(
170+
reduce_table=False, sort_table=True, add_caption=False
171+
)
160172
if table is not None:
161173
console.print(table)
162174

@@ -172,7 +184,9 @@ def pytask_execute_task_log_end(self, report: ExecutionReport) -> bool:
172184
self.update_reports(report)
173185
return True
174186

175-
def _generate_table(self, reduce_table: bool, sort_table: bool) -> Table | None:
187+
def _generate_table(
188+
self, reduce_table: bool, sort_table: bool, add_caption: bool
189+
) -> Table | None:
176190
"""Generate the table.
177191
178192
First, display all completed tasks and, then, all running tasks.
@@ -210,7 +224,19 @@ def _generate_table(self, reduce_table: bool, sort_table: bool) -> Table | None:
210224
relevant_reports, key=lambda report: report["name"]
211225
)
212226

213-
table = Table()
227+
if add_caption:
228+
caption_kwargs = {
229+
"caption": Text(
230+
f"Completed: {len(self._reports)}/{self._n_tasks}",
231+
style=Style(dim=True, italic=False),
232+
),
233+
"caption_justify": "right",
234+
"caption_style": None,
235+
}
236+
else:
237+
caption_kwargs = {}
238+
239+
table = Table(**caption_kwargs)
214240
table.add_column("Task", overflow="fold")
215241
table.add_column("Outcome")
216242
for report in relevant_reports:
@@ -237,10 +263,15 @@ def _generate_table(self, reduce_table: bool, sort_table: bool) -> Table | None:
237263
return table
238264

239265
def _update_table(
240-
self, reduce_table: bool = True, sort_table: bool = False
266+
self,
267+
reduce_table: bool = True,
268+
sort_table: bool = False,
269+
add_caption: bool = True,
241270
) -> None:
242271
"""Regenerate the table."""
243-
table = self._generate_table(reduce_table=reduce_table, sort_table=sort_table)
272+
table = self._generate_table(
273+
reduce_table=reduce_table, sort_table=sort_table, add_caption=add_caption
274+
)
244275
self._live_manager.update(table)
245276

246277
def update_running_tasks(self, new_running_task: Task) -> None:

tests/test_live.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ def test_live_execution_sequentially(capsys, tmp_path):
7777
assert "Outcome" not in captured.out
7878
assert "task_module.py::task_example" not in captured.out
7979
assert "running" not in captured.out
80+
assert "Completed: 0/x" not in captured.out
8081

8182
live_manager.resume()
8283
live_manager.start()
@@ -88,6 +89,7 @@ def test_live_execution_sequentially(capsys, tmp_path):
8889
assert "Outcome" in captured.out
8990
assert "task_module.py::task_example" in captured.out
9091
assert "running" in captured.out
92+
assert "Completed: 0/x" in captured.out
9193

9294
live_manager.start()
9395

@@ -104,6 +106,7 @@ def test_live_execution_sequentially(capsys, tmp_path):
104106
assert "task_module.py::task_example" in captured.out
105107
assert "running" not in captured.out
106108
assert TaskOutcome.SUCCESS.symbol in captured.out
109+
assert "Completed: 1/x" in captured.out
107110

108111

109112
@pytest.mark.unit
@@ -160,6 +163,7 @@ def test_live_execution_displays_subset_of_table(capsys, tmp_path, n_entries_in_
160163

161164
live_manager = LiveManager()
162165
live = LiveExecution(live_manager, n_entries_in_table, 1, "no_link")
166+
live._n_tasks = 2
163167

164168
live_manager.start()
165169
live.update_running_tasks(running_task)
@@ -170,6 +174,7 @@ def test_live_execution_displays_subset_of_table(capsys, tmp_path, n_entries_in_
170174
assert "Outcome" in captured.out
171175
assert "::task_running" in captured.out
172176
assert " running " in captured.out
177+
assert "Completed: 0/2" in captured.out
173178

174179
completed_task = Task(base_name="task_completed", path=path, function=lambda x: x)
175180
completed_task.short_name = "task_module.py::task_completed"
@@ -188,6 +193,7 @@ def test_live_execution_displays_subset_of_table(capsys, tmp_path, n_entries_in_
188193
assert "Outcome" in captured.out
189194
assert "::task_running" in captured.out
190195
assert " running " in captured.out
196+
assert "Completed: 1/2" in captured.out
191197

192198
if n_entries_in_table == 1:
193199
assert "task_module.py::task_completed" not in captured.out

0 commit comments

Comments
 (0)