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:
parent
a129b292e4
commit
003749fe3e
@ -15,6 +15,7 @@ import re
|
|||||||
from typing import Any
|
from typing import Any
|
||||||
import xml.etree.ElementTree as ET
|
import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
|
from mckicad.config import INLINE_RESULT_THRESHOLD
|
||||||
from mckicad.server import mcp
|
from mckicad.server import mcp
|
||||||
from mckicad.utils.file_utils import write_detail_file
|
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"],
|
stats["net_count"], stats["component_count"], stats["connection_count"],
|
||||||
)
|
)
|
||||||
|
|
||||||
result: dict[str, Any] = {
|
# Write full parsed data to output JSON (always — this is the complete data)
|
||||||
"success": True,
|
|
||||||
"format_detected": fmt,
|
|
||||||
"source_path": source_path,
|
|
||||||
**parsed,
|
|
||||||
}
|
|
||||||
|
|
||||||
# Write output JSON
|
|
||||||
if output_path:
|
if output_path:
|
||||||
out = os.path.abspath(os.path.expanduser(output_path))
|
out = os.path.abspath(os.path.expanduser(output_path))
|
||||||
os.makedirs(os.path.dirname(out) or ".", exist_ok=True)
|
os.makedirs(os.path.dirname(out) or ".", exist_ok=True)
|
||||||
@ -423,6 +417,31 @@ def import_netlist(
|
|||||||
source_path, "imported_netlist.json", parsed,
|
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
|
return result
|
||||||
|
|||||||
@ -430,3 +430,83 @@ class TestOutputFile:
|
|||||||
assert result["success"] is True
|
assert result["success"] is True
|
||||||
assert "output_path" in result
|
assert "output_path" in result
|
||||||
assert os.path.isfile(result["output_path"])
|
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
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user