Fix schematic validation to scan subdirectories for hierarchical sheets
Hierarchical KiCad projects store sub-sheets in subdirectories (e.g. sheets/). The flat os.listdir scan missed all of them. Use recursive glob to find .kicad_sch files at any depth under the project directory. Reported by ESP32-P4 project (agent thread message 025) — their 8 malformed property-private entries were all in sheets/ subdirectory.
This commit is contained in:
parent
56705cf345
commit
c1ddf0c5f7
@ -6,6 +6,7 @@ detail retrieval into a single module. Uses KiCad IPC when available
|
|||||||
for live data, falling back to file-based checks otherwise.
|
for live data, falling back to file-based checks otherwise.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import glob
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
@ -188,15 +189,13 @@ def validate_project(project_path: str) -> dict[str, Any]:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
issues.append(f"Error reading project file: {e}")
|
issues.append(f"Error reading project file: {e}")
|
||||||
|
|
||||||
# Validate schematic sexp integrity (all .kicad_sch files in project dir)
|
# Validate schematic sexp integrity (all .kicad_sch files, including sub-sheets)
|
||||||
if "schematic" in files:
|
if "schematic" in files:
|
||||||
project_dir = os.path.dirname(project_path)
|
project_dir = os.path.dirname(project_path)
|
||||||
sch_files = [
|
sch_files = sorted(
|
||||||
os.path.join(project_dir, f)
|
glob.glob(os.path.join(project_dir, "**", "*.kicad_sch"), recursive=True)
|
||||||
for f in os.listdir(project_dir)
|
)
|
||||||
if f.endswith(".kicad_sch")
|
for sch_path in sch_files:
|
||||||
]
|
|
||||||
for sch_path in sorted(sch_files):
|
|
||||||
issues.extend(_validate_schematic_sexp(sch_path))
|
issues.extend(_validate_schematic_sexp(sch_path))
|
||||||
|
|
||||||
# Optional live analysis via KiCad IPC
|
# Optional live analysis via KiCad IPC
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
"""Tests for project analysis and validation tools."""
|
"""Tests for project analysis and validation tools."""
|
||||||
|
|
||||||
|
import json
|
||||||
import os
|
import os
|
||||||
import textwrap
|
import textwrap
|
||||||
|
|
||||||
@ -134,3 +135,46 @@ class TestValidateSchematicSexp:
|
|||||||
path = self._write_sch(tmp_output_dir, "empty.kicad_sch", content)
|
path = self._write_sch(tmp_output_dir, "empty.kicad_sch", content)
|
||||||
issues = _validate_schematic_sexp(path)
|
issues = _validate_schematic_sexp(path)
|
||||||
assert issues == []
|
assert issues == []
|
||||||
|
|
||||||
|
def test_subdirectory_sheets_scanned(self, tmp_output_dir):
|
||||||
|
"""validate_project scans .kicad_sch files in subdirectories."""
|
||||||
|
from mckicad.tools.analysis import validate_project
|
||||||
|
|
||||||
|
# Create a minimal project structure with a sub-sheet in sheets/
|
||||||
|
pro_path = os.path.join(tmp_output_dir, "test.kicad_pro")
|
||||||
|
with open(pro_path, "w") as f:
|
||||||
|
json.dump({}, f)
|
||||||
|
|
||||||
|
# Root schematic — clean
|
||||||
|
root_sch = os.path.join(tmp_output_dir, "test.kicad_sch")
|
||||||
|
with open(root_sch, "w") as f:
|
||||||
|
f.write(textwrap.dedent("""\
|
||||||
|
(kicad_sch (version 20231120) (generator "eeschema")
|
||||||
|
(lib_symbols)
|
||||||
|
)
|
||||||
|
"""))
|
||||||
|
|
||||||
|
# Sub-sheet in sheets/ — has malformed property private
|
||||||
|
sheets_dir = os.path.join(tmp_output_dir, "sheets")
|
||||||
|
os.makedirs(sheets_dir)
|
||||||
|
sub_sch = os.path.join(sheets_dir, "sub.kicad_sch")
|
||||||
|
with open(sub_sch, "w") as f:
|
||||||
|
f.write(textwrap.dedent("""\
|
||||||
|
(kicad_sch (version 20231120) (generator "eeschema")
|
||||||
|
(lib_symbols
|
||||||
|
(symbol "Device:Crystal_GND24"
|
||||||
|
(property "private" "KLC_S3.3" malformed
|
||||||
|
(at 0 0 0)
|
||||||
|
(effects (font (size 1.27 1.27)) (hide yes))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
"""))
|
||||||
|
|
||||||
|
result = validate_project(pro_path)
|
||||||
|
# Should find the malformation in the sub-sheet
|
||||||
|
issues = result.get("issues") or []
|
||||||
|
sexp_issues = [i for i in issues if "private" in i]
|
||||||
|
assert len(sexp_issues) == 1
|
||||||
|
assert "sub.kicad_sch" in sexp_issues[0]
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user