Skip to content

Commit 043b36f

Browse files
authored
Add --show-locals which prints local variables in tracebacks. (#94)
1 parent 788b1fa commit 043b36f

File tree

10 files changed

+99
-11
lines changed

10 files changed

+99
-11
lines changed

README.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,8 @@ and pytest's many contributors, this project would not have been possible. Thank
193193
Citation
194194
--------
195195

196-
If you rely on pytask to manage your research project, please cite it with
196+
If you rely on pytask to manage your research project, please cite it with the following
197+
key to help others to discover the tool.
197198

198199
.. code-block::
199200

docs/changes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ all releases are available on `PyPI <https://pypi.org/project/pytask>`_ and
2121
- :gh:`88` adds a ``profile`` command to show information on tasks like duration and
2222
file size of products.
2323
- :gh:`93` fixes the display of parametrized arguments in the console.
24+
- :gh:`94` adds ``--show-locals`` which allows to print local variables in tracebacks.
2425

2526

2627
0.0.14 - 2021-03-23

docs/reference_guides/configuration.rst

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,20 @@ The options
130130
pdb = True
131131
132132
133+
.. confval:: show_locals
134+
135+
If you want to print local variables of each stack frame in the tracebacks, set this
136+
value to true.
137+
138+
.. code-block:: console
139+
140+
pytask build --show-locals
141+
142+
.. code-block:: ini
143+
144+
show_locals = True
145+
146+
133147
.. confval:: strict_markers
134148

135149
If you want to raise an error for unregistered markers, pass

docs/tutorials/how_to_debug.rst

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,17 @@ be more productive and gain more confidence in your code.
1010
To facilitate debugging, pytask offers two command-line options.
1111

1212

13+
Tracebacks
14+
----------
15+
16+
You can enrich the display of tracebacks by show local variables in each stack frame.
17+
Just execute pytask with
18+
19+
.. code-block:: console
20+
21+
$ pytask --show-locals
22+
23+
1324
Debugging
1425
---------
1526

@@ -30,7 +41,7 @@ prompt will enter the debugger enabling you to discover the source of the except
3041
.. tip::
3142

3243
Instead of Python's :mod:`pdb`, use `pdb++ <https://github.com/pdbpp/pdbpp>`_ which
33-
is more convenient, colorful has some useful features like the `sticky mode
44+
is more convenient, colorful, and has some useful features like the `sticky mode
3445
<https://github.com/pdbpp/pdbpp#sticky-mode>`_.
3546

3647

src/_pytask/cli.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ 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
4647
from _pytask import database
4748
from _pytask import debugging
4849
from _pytask import execute
@@ -61,6 +62,7 @@ def pytask_add_hooks(pm):
6162
pm.register(collect)
6263
pm.register(collect_command)
6364
pm.register(config)
65+
pm.register(console)
6466
pm.register(database)
6567
pm.register(debugging)
6668
pm.register(execute)

src/_pytask/collect.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ def pytask_collect_log(session, reports, tasks):
265265

266266
console.print()
267267

268-
console.print(Traceback.from_exception(*report.exc_info))
268+
console.print(Traceback.from_exception(*report.exc_info, show_locals=True))
269269

270270
console.print()
271271

src/_pytask/console.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,14 @@
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
610
from rich.console import Console
711
from rich.tree import Tree
812

13+
914
_IS_WSL = "IS_WSL" in os.environ or "WSL_DISTRO_NAME" in os.environ
1015
_IS_WINDOWS_TERMINAL = "WT_SESSION" in os.environ
1116
_IS_WINDOWS = sys.platform == "win32"
@@ -29,6 +34,28 @@
2934
console = Console(color_system=_COLOR_SYSTEM)
3035

3136

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+
3259
def format_strings_as_flat_tree(strings: List[str], title: str, icon: str) -> str:
3360
"""Format list of strings as flat tree."""
3461
tree = Tree(title)

src/_pytask/execute.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ def pytask_execute_task_log_end(report):
161161
@hookimpl
162162
def pytask_execute_log_end(session, reports):
163163
session.execution_end = time.time()
164+
show_locals = session.config["show_locals"]
164165

165166
n_successful = sum(report.success for report in reports)
166167
n_failed = len(reports) - n_successful
@@ -183,7 +184,9 @@ def pytask_execute_log_end(session, reports):
183184

184185
console.print()
185186

186-
console.print(Traceback.from_exception(*report.exc_info))
187+
console.print(
188+
Traceback.from_exception(*report.exc_info, show_locals=show_locals)
189+
)
187190

188191
console.print()
189192
show_capture = session.config["show_capture"]

src/_pytask/resolve_dependencies.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -119,13 +119,16 @@ def _has_node_changed(task_name: str, node_dict):
119119
try:
120120
state = node.state()
121121
except NodeNotFoundError:
122-
return True
123-
try:
124-
state_in_db = State[task_name, node.name].state
125-
except orm.ObjectNotFound:
126-
return True
127-
128-
return state != state_in_db
122+
out = True
123+
else:
124+
try:
125+
state_in_db = State[task_name, node.name].state
126+
except orm.ObjectNotFound:
127+
out = True
128+
else:
129+
out = state != state_in_db
130+
131+
return out
129132

130133

131134
def _check_if_dag_has_cycles(dag):

tests/test_console.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import textwrap
2+
3+
import pytest
4+
from pytask import cli
5+
6+
7+
@pytest.mark.end_to_end
8+
def test_printing_of_local_variables(tmp_path, runner):
9+
source = """
10+
def task_dummy():
11+
a = 1
12+
helper()
13+
14+
def helper():
15+
b = 2
16+
raise Exception
17+
"""
18+
tmp_path.joinpath("task_dummy.py").write_text(textwrap.dedent(source))
19+
20+
result = runner.invoke(cli, [tmp_path.as_posix(), "--show-locals"])
21+
assert result.exit_code == 1
22+
23+
captured = result.output
24+
assert " locals " in captured
25+
assert "a = 1" in captured
26+
assert "b = 2" in captured

0 commit comments

Comments
 (0)