Skip to content

Commit 7d1df94

Browse files
committed
fix(runner): don't surface benign LVS-config warnings as fail summary (1.3.1)
The runner captures every WARNING+ log emitted during a check and uses the first one as the one-line FAIL summary when the check itself hasn't set `details`. "Missing LVS configuration variable EXTRACT_CREATE_SUBCUT" (and the eight sibling messages from config.start_be_check) fire on almost every project whose lvs_config.*.json omits the optional LVS optimisation keys, and they fire before run_oeb_check / run_be_checks starts — so they always win the first-captured-warning race and mask the real failure reason. Filter them out of `fallback_detail` (and the dim trailing hint line) via a small substring allow-list. Messages still go to the log at WARNING level so a curious user can still see them. Factored the classifier into _warning_filters.py so tests can import it without dragging in pya/KLayout through check_manager. Includes 3 unit tests covering the benign-match, real-error, and no-regex-in-substring-list invariants. Made-with: Cursor
1 parent 162ec1b commit 7d1df94

4 files changed

Lines changed: 76 additions & 4 deletions

File tree

src/cf_precheck/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "1.3.0"
1+
__version__ = "1.3.1"
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
"""Classifiers for the captured-warning fallback used by runner.py.
2+
3+
Lives in its own tiny module so unit tests can import the classifier without
4+
pulling in the full check stack (which transitively imports pya/KLayout and
5+
only works inside the precheck Docker image).
6+
"""
7+
8+
from __future__ import annotations
9+
10+
11+
# Warnings emitted during setup that must stay visible in the log but must
12+
# NOT become the one-line FAIL summary for a check. Each entry is a plain
13+
# substring match against the captured log message.
14+
#
15+
# Example: "Missing LVS configuration variable EXTRACT_CREATE_SUBCUT" fires
16+
# for almost every user project whose lvs_config.*.json doesn't populate the
17+
# optional LVS optimisation keys, and it always fires before the real OEB
18+
# or LVS failure reason. Without this filter the real error gets masked.
19+
BENIGN_WARNING_SUBSTRINGS: tuple[str, ...] = (
20+
"Missing LVS configuration variable ",
21+
)
22+
23+
24+
def is_benign_warning(message: str) -> bool:
25+
"""Return True if a captured WARNING shouldn't be surfaced as fail detail."""
26+
return any(needle in message for needle in BENIGN_WARNING_SUBSTRINGS)

src/cf_precheck/runner.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from rich.text import Text
1313

1414
from cf_precheck import __version__
15+
from cf_precheck._warning_filters import is_benign_warning
1516
from cf_precheck.check_manager import ALL_CHECKS, build_sequence, get_check_manager
1617
from cf_precheck.config import file_hash, get_project_config, uncompress_gds
1718
from cf_precheck.logging import console, error_capture
@@ -161,6 +162,11 @@ def run_precheck(
161162
devnull.close()
162163

163164
captured_errors = error_capture.stop()
165+
# Benign setup warnings (e.g. "Missing LVS configuration variable FOO")
166+
# get logged before the real failure reason, so without this filter
167+
# they end up as the FAIL summary line and mask the actual problem.
168+
# Keep them in the log — just don't surface them as the fail summary.
169+
significant_errors = [m for m in captured_errors if not is_benign_warning(m)]
164170

165171
check_report = getattr(check, "report", None)
166172
check_details = getattr(check, "details", None)
@@ -177,7 +183,7 @@ def run_precheck(
177183
)
178184
else:
179185
status_str = "[fail]FAIL[/fail]"
180-
fallback_detail = captured_errors[0] if captured_errors else None
186+
fallback_detail = significant_errors[0] if significant_errors else None
181187
result = CheckResult(
182188
name=ref,
183189
surname=surname,
@@ -195,8 +201,8 @@ def run_precheck(
195201
console.file.flush()
196202
console.print(_format_check_line(prefix, dots, status_str, elapsed))
197203

198-
if not passed and captured_errors:
199-
brief = captured_errors[0]
204+
if not passed and significant_errors:
205+
brief = significant_errors[0]
200206
if len(brief) > 120:
201207
brief = brief[:117] + "..."
202208
console.print(f" [dim]{brief}[/dim]")

tests/test_runner_warnings.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
"""Tests for the fail-summary benign-warning filter.
2+
3+
The runner captures any WARNING/ERROR logs emitted during a check and uses
4+
the first one as the user-visible fail summary when the check itself did not
5+
set ``details``. Benign setup warnings (e.g. missing optional LVS config
6+
variables) must be excluded from that fallback so real failure reasons
7+
remain visible.
8+
"""
9+
10+
from __future__ import annotations
11+
12+
from cf_precheck._warning_filters import (
13+
BENIGN_WARNING_SUBSTRINGS,
14+
is_benign_warning,
15+
)
16+
17+
18+
def test_missing_lvs_config_variable_is_benign() -> None:
19+
assert is_benign_warning(
20+
"Missing LVS configuration variable EXTRACT_CREATE_SUBCUT"
21+
)
22+
assert is_benign_warning(
23+
"Missing LVS configuration variable LVS_FLATTEN"
24+
)
25+
26+
27+
def test_real_error_is_not_benign() -> None:
28+
assert not is_benign_warning(
29+
"OEB FAILED: could not find LVS configuration file lvs_config.json"
30+
)
31+
assert not is_benign_warning("Magic DRC reported 12 errors in layout")
32+
assert not is_benign_warning("")
33+
34+
35+
def test_benign_substrings_are_plain_strings_not_regex() -> None:
36+
# Sanity: keep the filter a plain-substring list so it's easy to reason
37+
# about and impossible to accidentally disable via user-supplied text.
38+
for needle in BENIGN_WARNING_SUBSTRINGS:
39+
assert isinstance(needle, str) and needle
40+
assert not any(c in needle for c in "()[]{}.*+?^$\\|")

0 commit comments

Comments
 (0)