Skip to content

Commit fa3725a

Browse files
authored
Print directory change notifications in Flow API backends (#512)
Extends the Entering directory / Leaving directory notifications from Print directory change notifications around tool execution #511 to the Flow API's _run_tool() in edalize/flows/edaflow.py Adds unit tests covering both legacy and Flow API _run_tool() directory notifications
1 parent 4d82d96 commit fa3725a

File tree

2 files changed

+111
-0
lines changed

2 files changed

+111
-0
lines changed

edalize/flows/edaflow.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,9 @@ def _run_tool(self, cmd, args=[], cwd=None, quiet=False, env={}):
343343
logger.debug("args : " + " ".join(args))
344344

345345
capture_output = quiet and not (self.verbose or self.stdout or self.stderr)
346+
abs_cwd = os.path.abspath(cwd) if cwd else None
347+
if abs_cwd:
348+
print(f"Entering directory '{abs_cwd}'")
346349
try:
347350
cp = run(
348351
[cmd] + args,
@@ -369,6 +372,8 @@ def _run_tool(self, cmd, args=[], cwd=None, quiet=False, env={}):
369372
logger.debug(e.stderr)
370373

371374
raise RuntimeError(_s)
375+
if abs_cwd:
376+
print(f"Leaving directory '{abs_cwd}'")
372377
return cp.returncode, cp.stdout, cp.stderr
373378

374379
def build(self):

tests/test_run_tool_dirnotify.py

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import os
2+
from unittest.mock import patch, MagicMock
3+
import subprocess
4+
5+
import pytest
6+
7+
8+
# ── Legacy API ──────────────────────────────────────────────────────────
9+
10+
11+
def _make_legacy_tool(work_root):
12+
"""Create a minimal legacy Edatool instance with enough state to call _run_tool."""
13+
from edalize.edatool import Edatool
14+
15+
obj = object.__new__(Edatool)
16+
obj.work_root = str(work_root)
17+
obj.verbose = False
18+
obj.stdout = None
19+
obj.stderr = None
20+
return obj
21+
22+
23+
@patch("edalize.edatool.run")
24+
def test_legacy_run_tool_prints_dir_notifications(mock_run, tmp_path, capsys):
25+
mock_run.return_value = subprocess.CompletedProcess(
26+
args=["true"], returncode=0, stdout=None, stderr=None
27+
)
28+
29+
tool = _make_legacy_tool(tmp_path)
30+
tool._run_tool("true")
31+
32+
captured = capsys.readouterr().out
33+
abs_path = str(os.path.abspath(tmp_path))
34+
assert f"Entering directory '{abs_path}'" in captured
35+
assert f"Leaving directory '{abs_path}'" in captured
36+
37+
38+
@patch("edalize.edatool.run")
39+
def test_legacy_run_tool_no_leaving_on_error(mock_run, tmp_path, capsys):
40+
mock_run.side_effect = FileNotFoundError("not found")
41+
42+
tool = _make_legacy_tool(tmp_path)
43+
with pytest.raises(RuntimeError):
44+
tool._run_tool("nonexistent_cmd")
45+
46+
captured = capsys.readouterr().out
47+
abs_path = str(os.path.abspath(tmp_path))
48+
assert f"Entering directory '{abs_path}'" in captured
49+
assert "Leaving directory" not in captured
50+
51+
52+
# ── Flow API ────────────────────────────────────────────────────────────
53+
54+
55+
def _make_flow_tool():
56+
"""Create a minimal Edaflow-like object to test _run_tool."""
57+
from edalize.flows.edaflow import Edaflow
58+
59+
obj = object.__new__(Edaflow)
60+
obj.verbose = False
61+
obj.stdout = None
62+
obj.stderr = None
63+
return obj
64+
65+
66+
@patch("edalize.flows.edaflow.run")
67+
def test_flow_run_tool_prints_dir_notifications(mock_run, tmp_path, capsys):
68+
mock_run.return_value = subprocess.CompletedProcess(
69+
args=["true"], returncode=0, stdout=None, stderr=None
70+
)
71+
72+
flow = _make_flow_tool()
73+
flow._run_tool("true", cwd=str(tmp_path))
74+
75+
captured = capsys.readouterr().out
76+
abs_path = str(os.path.abspath(tmp_path))
77+
assert f"Entering directory '{abs_path}'" in captured
78+
assert f"Leaving directory '{abs_path}'" in captured
79+
80+
81+
@patch("edalize.flows.edaflow.run")
82+
def test_flow_run_tool_no_leaving_on_error(mock_run, tmp_path, capsys):
83+
mock_run.side_effect = FileNotFoundError("not found")
84+
85+
flow = _make_flow_tool()
86+
with pytest.raises(RuntimeError):
87+
flow._run_tool("nonexistent_cmd", cwd=str(tmp_path))
88+
89+
captured = capsys.readouterr().out
90+
abs_path = str(os.path.abspath(tmp_path))
91+
assert f"Entering directory '{abs_path}'" in captured
92+
assert "Leaving directory" not in captured
93+
94+
95+
@patch("edalize.flows.edaflow.run")
96+
def test_flow_run_tool_no_cwd_skips_notifications(mock_run, capsys):
97+
mock_run.return_value = subprocess.CompletedProcess(
98+
args=["true"], returncode=0, stdout=None, stderr=None
99+
)
100+
101+
flow = _make_flow_tool()
102+
flow._run_tool("true")
103+
104+
captured = capsys.readouterr().out
105+
assert "Entering directory" not in captured
106+
assert "Leaving directory" not in captured

0 commit comments

Comments
 (0)