Skip to content

Commit feec8de

Browse files
authored
Add a dynamic spinner to show the progress during collection. (#96)
1 parent 05b6dd1 commit feec8de

8 files changed

Lines changed: 62 additions & 79 deletions

File tree

docs/changes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ all releases are available on `PyPI <https://pypi.org/project/pytask>`_ and
2222
file size of products.
2323
- :gh:`93` fixes the display of parametrized arguments in the console.
2424
- :gh:`94` adds ``--show-locals`` which allows to print local variables in tracebacks.
25+
- :gh:`96` implements a spinner to show the progress during the collection.
2526

2627

2728
0.0.14 - 2021-03-23

docs/tutorials/how_to_debug.rst

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,17 @@
11
How to debug
22
============
33

4-
The debug mode is one of pytask's biggest strength. Whenever you encounter an error in
5-
one of your tasks, jump right into the code and inspect the cause of the exception.
4+
Whenever you encounter an error in one of your tasks, pytask offers multiple ways which
5+
help you to gain more information on the root cause.
66

7-
Quick and easy feedback through a debugger is immensely valuable because it helps you to
8-
be more productive and gain more confidence in your code.
9-
10-
To facilitate debugging, pytask offers two command-line options.
7+
Through quick and easy feedback you are more productive and gain more confidence in your
8+
code.
119

1210

1311
Tracebacks
1412
----------
1513

16-
You can enrich the display of tracebacks by show local variables in each stack frame.
14+
You can enrich the display of tracebacks by showing local variables in each stack frame.
1715
Just execute pytask with
1816

1917
.. code-block:: console

src/_pytask/cli.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ def pytask_add_hooks(pm):
4343
from _pytask import collect
4444
from _pytask import collect_command
4545
from _pytask import config
46-
from _pytask import console
4746
from _pytask import database
4847
from _pytask import debugging
4948
from _pytask import execute
@@ -62,7 +61,6 @@ def pytask_add_hooks(pm):
6261
pm.register(collect)
6362
pm.register(collect_command)
6463
pm.register(config)
65-
pm.register(console)
6664
pm.register(database)
6765
pm.register(debugging)
6866
pm.register(execute)

src/_pytask/collect.py

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from _pytask.config import hookimpl
1212
from _pytask.config import IS_FILE_SYSTEM_CASE_SENSITIVE
1313
from _pytask.console import console
14+
from _pytask.console import generate_collection_status
1415
from _pytask.enums import ColorCode
1516
from _pytask.exceptions import CollectionError
1617
from _pytask.mark import has_marker
@@ -20,6 +21,7 @@
2021
from _pytask.nodes import reduce_node_name
2122
from _pytask.path import find_case_sensitive_path
2223
from _pytask.report import CollectionReport
24+
from rich.live import Live
2325
from rich.traceback import Traceback
2426

2527

@@ -28,17 +30,14 @@ def pytask_collect(session):
2830
"""Collect tasks."""
2931
session.collection_start = time.time()
3032

31-
reports = _collect_from_paths(session)
32-
tasks = _extract_successfully_collected_tasks_from_reports(reports)
33+
with Live(generate_collection_status(0), console=console, transient=True) as live:
34+
_collect_from_paths(session, live)
3335

3436
try:
35-
session.hook.pytask_collect_modify_tasks(session=session, tasks=tasks)
37+
session.hook.pytask_collect_modify_tasks(session=session, tasks=session.tasks)
3638
except Exception:
3739
report = CollectionReport.from_exception(exc_info=sys.exc_info())
38-
reports.append(report)
39-
40-
session.collection_reports = reports
41-
session.tasks = tasks
40+
session.collection_reports.append(report)
4241

4342
session.hook.pytask_collect_log(
4443
session=session, reports=session.collection_reports, tasks=session.tasks
@@ -47,21 +46,21 @@ def pytask_collect(session):
4746
return True
4847

4948

50-
def _collect_from_paths(session):
49+
def _collect_from_paths(session, live=None):
5150
"""Collect tasks from paths.
5251
5352
Go through all paths, check if the path is ignored, and collect the file if not.
5453
5554
"""
56-
collected_reports = session.collection_reports
5755
for path in _not_ignored_paths(session.config["paths"], session):
5856
reports = session.hook.pytask_collect_file_protocol(
59-
session=session, path=path, reports=collected_reports
57+
session=session, path=path, reports=session.collection_reports
6058
)
6159
if reports is not None:
62-
collected_reports.extend(reports)
63-
64-
return collected_reports
60+
session.collection_reports.extend(reports)
61+
session.tasks.extend(i.node for i in reports if i.successful)
62+
if live is not None:
63+
live.update(generate_collection_status(len(session.tasks)))
6564

6665

6766
@hookimpl
@@ -230,11 +229,6 @@ def _not_ignored_paths(paths: List[Path], session) -> Generator[Path, None, None
230229
yield path
231230

232231

233-
def _extract_successfully_collected_tasks_from_reports(reports):
234-
"""Extract successfully collected tasks from reports."""
235-
return [i.node for i in reports if i.successful]
236-
237-
238232
@hookimpl
239233
def pytask_collect_log(session, reports, tasks):
240234
"""Log collection."""

src/_pytask/console.py

Lines changed: 8 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,8 @@
33
import sys
44
from typing import List
55

6-
import click
7-
from _pytask.config import hookimpl
8-
from _pytask.shared import convert_truthy_or_falsy_to_bool
9-
from _pytask.shared import get_first_non_none_value
106
from rich.console import Console
7+
from rich.status import Status
118
from rich.tree import Tree
129

1310

@@ -34,28 +31,6 @@
3431
console = Console(color_system=_COLOR_SYSTEM)
3532

3633

37-
@hookimpl
38-
def pytask_extend_command_line_interface(cli):
39-
show_locals_option = click.Option(
40-
["--show-locals"],
41-
is_flag=True,
42-
default=None,
43-
help="Show local variables in tracebacks.",
44-
)
45-
cli.commands["build"].params.append(show_locals_option)
46-
47-
48-
@hookimpl
49-
def pytask_parse_config(config, config_from_file, config_from_cli):
50-
config["show_locals"] = get_first_non_none_value(
51-
config_from_cli,
52-
config_from_file,
53-
key="show_locals",
54-
default=False,
55-
callback=convert_truthy_or_falsy_to_bool,
56-
)
57-
58-
5934
def format_strings_as_flat_tree(strings: List[str], title: str, icon: str) -> str:
6035
"""Format list of strings as flat tree."""
6136
tree = Tree(title)
@@ -84,3 +59,10 @@ def escape_squared_brackets(string: str) -> str:
8459
8560
"""
8661
return string.replace("[", "\\[")
62+
63+
64+
def generate_collection_status(n_collected_tasks):
65+
"""Generate the status object to display the progress during collection."""
66+
return Status(
67+
f"Collected {n_collected_tasks} tasks.", refresh_per_second=4, spinner="dots"
68+
)

src/_pytask/debugging.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@ def pytask_extend_command_line_interface(cli):
3737
),
3838
metavar="module_name:class_name",
3939
),
40+
click.Option(
41+
["--show-locals"],
42+
is_flag=True,
43+
default=None,
44+
help="Show local variables in tracebacks.",
45+
),
4046
]
4147
cli.commands["build"].params.extend(additional_parameters)
4248

@@ -65,6 +71,13 @@ def pytask_parse_config(config, config_from_cli, config_from_file):
6571
default=None,
6672
callback=_pdbcls_callback,
6773
)
74+
config["show_locals"] = get_first_non_none_value(
75+
config_from_cli,
76+
config_from_file,
77+
key="show_locals",
78+
default=False,
79+
callback=convert_truthy_or_falsy_to_bool,
80+
)
6881

6982

7083
def _pdbcls_callback(x):

tests/test_console.py

Lines changed: 0 additions & 26 deletions
This file was deleted.

tests/test_debugging.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import pytest
77
from _pytask.debugging import _pdbcls_callback
8+
from pytask import cli
89

910
try:
1011
import pexpect
@@ -422,3 +423,25 @@ def test_pdb_used_outside_test(tmp_path):
422423
child.expect("Pdb")
423424
child.sendeof()
424425
_flush(child)
426+
427+
428+
@pytest.mark.end_to_end
429+
def test_printing_of_local_variables(tmp_path, runner):
430+
source = """
431+
def task_dummy():
432+
a = 1
433+
helper()
434+
435+
def helper():
436+
b = 2
437+
raise Exception
438+
"""
439+
tmp_path.joinpath("task_dummy.py").write_text(textwrap.dedent(source))
440+
441+
result = runner.invoke(cli, [tmp_path.as_posix(), "--show-locals"])
442+
assert result.exit_code == 1
443+
444+
captured = result.output
445+
assert " locals " in captured
446+
assert "a = 1" in captured
447+
assert "b = 2" in captured

0 commit comments

Comments
 (0)