Cap import_netlist inline response size for large netlists

Netlists exceeding INLINE_RESULT_THRESHOLD (20 nets) now return a
compact summary with the top nets by connection count as a preview.
Full data is always written to the sidecar JSON file. Small netlists
still return everything inline.
This commit is contained in:
Ryan Malloy 2026-03-05 17:47:49 -07:00
parent a129b292e4
commit 003749fe3e
2 changed files with 108 additions and 9 deletions

View File

@ -15,6 +15,7 @@ import re
from typing import Any
import xml.etree.ElementTree as ET
from mckicad.config import INLINE_RESULT_THRESHOLD
from mckicad.server import mcp
from mckicad.utils.file_utils import write_detail_file
@ -405,14 +406,7 @@ def import_netlist(
stats["net_count"], stats["component_count"], stats["connection_count"],
)
result: dict[str, Any] = {
"success": True,
"format_detected": fmt,
"source_path": source_path,
**parsed,
}
# Write output JSON
# Write full parsed data to output JSON (always — this is the complete data)
if output_path:
out = os.path.abspath(os.path.expanduser(output_path))
os.makedirs(os.path.dirname(out) or ".", exist_ok=True)
@ -423,6 +417,31 @@ def import_netlist(
source_path, "imported_netlist.json", parsed,
)
result["output_path"] = out
result: dict[str, Any] = {
"success": True,
"format_detected": fmt,
"source_path": source_path,
"output_path": out,
"statistics": stats,
}
nets = parsed["nets"]
if stats["net_count"] <= INLINE_RESULT_THRESHOLD:
# Small netlist — return everything inline
result["nets"] = nets
result["components"] = parsed["components"]
if "pin_metadata" in parsed:
result["pin_metadata"] = parsed["pin_metadata"]
else:
# Large netlist — compact summary inline, full data in output file
# Sort nets by connection count (most connected first) for useful preview
sorted_nets = sorted(nets.items(), key=lambda kv: len(kv[1]), reverse=True)
result["nets_preview"] = dict(sorted_nets[:INLINE_RESULT_THRESHOLD])
result["nets_preview_note"] = (
f"Showing top {INLINE_RESULT_THRESHOLD} of {stats['net_count']} nets "
f"by connection count. Full data in output_path."
)
# Include component count but not full component dict
result["component_refs"] = sorted(parsed["components"].keys())
return result

View File

@ -430,3 +430,83 @@ class TestOutputFile:
assert result["success"] is True
assert "output_path" in result
assert os.path.isfile(result["output_path"])
def test_large_netlist_returns_preview(self, tmp_output_dir):
"""Netlists exceeding INLINE_RESULT_THRESHOLD return a preview, not full data."""
from mckicad.config import INLINE_RESULT_THRESHOLD
from mckicad.tools.netlist import import_netlist
# Generate a netlist with more nets than the threshold
net_count = INLINE_RESULT_THRESHOLD + 5
net_lines = []
comp_lines = []
refs_seen: set[str] = set()
for i in range(1, net_count + 1):
ref_a = f"R{i}"
ref_b = f"C{i}"
comp_lines.append(f'<comp ref="{ref_a}"><value>{i}k</value></comp>')
comp_lines.append(f'<comp ref="{ref_b}"><value>{i}00nF</value></comp>')
refs_seen.update([ref_a, ref_b])
net_lines.append(
f'<net code="{i}" name="NET{i}">'
f'<node ref="{ref_a}" pin="1"/>'
f'<node ref="{ref_b}" pin="2"/>'
f'</net>'
)
xml = (
'<export version="D"><components>'
+ "".join(comp_lines)
+ "</components><nets>"
+ "".join(net_lines)
+ "</nets></export>"
)
src = os.path.join(tmp_output_dir, "large.xml")
with open(src, "w") as f:
f.write(xml)
result = import_netlist(source_path=src)
assert result["success"] is True
assert result["statistics"]["net_count"] == net_count
# Should NOT have full nets inline
assert "nets" not in result
# Should have preview
assert "nets_preview" in result
assert len(result["nets_preview"]) == INLINE_RESULT_THRESHOLD
assert "nets_preview_note" in result
# Should have component refs list instead of full component dict
assert "component_refs" in result
assert "components" not in result
# Full data should be in the output file
assert os.path.isfile(result["output_path"])
with open(result["output_path"]) as f:
full_data = json.load(f)
assert len(full_data["nets"]) == net_count
def test_small_netlist_returns_inline(self, tmp_output_dir):
"""Netlists within INLINE_RESULT_THRESHOLD return full data inline."""
from mckicad.tools.netlist import import_netlist
xml = textwrap.dedent("""\
<export version="D">
<components><comp ref="R1"><value>1k</value></comp></components>
<nets>
<net code="1" name="GND"><node ref="R1" pin="2"/></net>
</nets>
</export>
""")
src = os.path.join(tmp_output_dir, "small.xml")
with open(src, "w") as f:
f.write(xml)
result = import_netlist(source_path=src)
assert result["success"] is True
# Should have full data inline
assert "nets" in result
assert "components" in result
# Should NOT have preview keys
assert "nets_preview" not in result
assert "component_refs" not in result