fix(seedgo): Debug_Print detector regex matched print( inside string literals - strip string content before matching (+regression test); flatten depth-5 nesting in cli_ux_check. The auditor was the last branch under 100 - fleet now genuinely 17/17 (FPLAN-0333)
This commit is contained in:
@@ -53,6 +53,11 @@ and README to the house pattern: 17/17 branches at 100%.
|
||||
- **Fleet-100 sweep**: 15 branches gained Quick Start READMEs and/or
|
||||
Usage/Examples help sections — each owner fixed their own front against the
|
||||
new gate.
|
||||
- **Debug_Print detector hardened**: the regex-based checker matched `print(`
|
||||
inside string literals (flagging cli_ux_check's own error messages — the
|
||||
auditor was the last branch under 100%). String content is now stripped
|
||||
before matching, with a regression test; plus a depth-5 nesting refactor in
|
||||
the same file.
|
||||
|
||||
**v2.7.2** — everything merged since v2.7.1, headlined by the compass decision
|
||||
engine v2: curation with supersedes links + write-time conflict advisories
|
||||
|
||||
@@ -214,20 +214,10 @@ def _find_function(tree: ast.Module, name: str) -> Optional[ast.FunctionDef]:
|
||||
|
||||
|
||||
def _collect_string_constants(func_node: ast.FunctionDef) -> List[str]:
|
||||
"""
|
||||
Extract all string constants from a function body, including strings
|
||||
inside f-strings (ast.JoinedStr -> ast.Constant).
|
||||
"""
|
||||
strings: List[str] = []
|
||||
for node in ast.walk(func_node):
|
||||
if isinstance(node, ast.Constant) and isinstance(node.value, str):
|
||||
strings.append(node.value)
|
||||
elif isinstance(node, ast.JoinedStr):
|
||||
# f-string: extract string parts
|
||||
for part in node.values:
|
||||
if isinstance(part, ast.Constant) and isinstance(part.value, str):
|
||||
strings.append(part.value)
|
||||
return strings
|
||||
"""Extract all string constants from a function body, including f-string parts."""
|
||||
return [
|
||||
node.value for node in ast.walk(func_node) if isinstance(node, ast.Constant) and isinstance(node.value, str)
|
||||
]
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@@ -34,6 +34,9 @@ _DOCTEST_RE = re.compile(r"^\s*(\.\.\.|>>>)\s")
|
||||
# Test file name patterns
|
||||
_TEST_FILE_RE = re.compile(r"^(test_.+|.+_test|conftest)\.py$")
|
||||
|
||||
# String literals — strip content before regex to avoid false positives on print( inside strings
|
||||
_STRING_LITERAL_RE = re.compile(r'""".*?"""|\'\'\'.*?\'\'\'|"(?:[^"\\]|\\.)*"|\'(?:[^\'\\]|\\.)*\'')
|
||||
|
||||
|
||||
def _is_in_main_block(lines: list[str], lineno: int) -> bool:
|
||||
"""
|
||||
@@ -108,8 +111,9 @@ def _scan_file(file_path: Path) -> tuple[list[int], str | None]:
|
||||
if _DOCTEST_RE.match(line):
|
||||
continue
|
||||
|
||||
# Strip inline comments before checking for print(
|
||||
# Strip inline comments and string literal contents before checking
|
||||
code_part = line.split("#")[0]
|
||||
code_part = _STRING_LITERAL_RE.sub('""', code_part)
|
||||
|
||||
if not _PRINT_RE.search(code_part):
|
||||
continue
|
||||
|
||||
@@ -329,6 +329,22 @@ def test_debug_print_check_bypass_respected(tmp_path):
|
||||
assert result["score"] == 100, f"Bypass should yield 100: {result}"
|
||||
|
||||
|
||||
def test_debug_print_string_literal_not_flagged(tmp_path):
|
||||
"""print() mentioned inside string literals must not trigger false positives."""
|
||||
f = tmp_path / "messages.py"
|
||||
f.write_text(
|
||||
'"""Module with print() in docstring."""\n\n'
|
||||
"def check():\n"
|
||||
' msg = "use console.print() not bare print()"\n'
|
||||
" return msg\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
from aipass.seedgo.apps.handlers.aipass_standards.debug_print_check import check_module
|
||||
|
||||
result = check_module(str(f))
|
||||
assert result["score"] == 100, f"print() inside strings should not flag: {result}"
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# 6. deep_nesting_check
|
||||
# ===========================================================================
|
||||
|
||||
Reference in New Issue
Block a user