feat(map): add edge-center delta stats, thickness overlay, and layout fix
- Add edge-center sensor pair tables and delta calculations per wafer family. - Parse and interpolate wafer thickness CSV data for offscreen visualization. - Refactor ReadoutPanel layout using Item + anchors to fix right-margin clipping. - Compact E-C Delta text format to fit standard sidebar width. - Add pytest suite covering delta calculations, layout pairs, and thickness CSV.
This commit is contained in:
@@ -47,16 +47,89 @@ def test_thickness_properties():
|
||||
|
||||
|
||||
def test_thickness_setter_updates_data():
|
||||
"""Setting thicknessData updates _thickness_data."""
|
||||
"""Setting thicknessData stores [x, y, t2] triples."""
|
||||
from pygui.backend.visualization.wafer_map_item import WaferMapItem
|
||||
|
||||
item = WaferMapItem()
|
||||
item._rebuild_thickness = MagicMock()
|
||||
|
||||
item.thicknessData = [1.0, 2.0, 3.0]
|
||||
item.thicknessData = [[0.0, 10.0, 1.5], [5.0, -5.0, 2.0]]
|
||||
|
||||
assert item._thickness_data == [1.0, 2.0, 3.0]
|
||||
assert item._thickness_data == [[0.0, 10.0, 1.5], [5.0, -5.0, 2.0]]
|
||||
assert item._rebuild_thickness.called
|
||||
assert item.hasThickness is True
|
||||
|
||||
|
||||
THICKNESS_HEADER = "Lot Start Time,RC,Site#,Slot#,T2,NGOF,Wafer X,Wafer Y\n"
|
||||
|
||||
|
||||
def _write_csv(tmp_path, body, header=THICKNESS_HEADER):
|
||||
p = tmp_path / "thickness.csv"
|
||||
p.write_text(header + body)
|
||||
return str(p)
|
||||
|
||||
|
||||
def test_parse_thickness_csv_valid(tmp_path):
|
||||
from pygui.backend.visualization.wafer_map_item import parse_thickness_csv
|
||||
|
||||
path = _write_csv(tmp_path,
|
||||
"t,1,1,7,1.5,0,10.0,-20.0\n"
|
||||
"t,1,2,7,2.5,0,-30.0,40.0\n")
|
||||
points, err = parse_thickness_csv(path)
|
||||
assert err == ""
|
||||
assert points == [[10.0, -20.0, 1.5], [-30.0, 40.0, 2.5]]
|
||||
|
||||
|
||||
def test_parse_thickness_csv_first_slot_only(tmp_path):
|
||||
"""Rows after the Slot# changes belong to another wafer and are skipped."""
|
||||
from pygui.backend.visualization.wafer_map_item import parse_thickness_csv
|
||||
|
||||
path = _write_csv(tmp_path,
|
||||
"t,1,1,7,1.5,0,10.0,-20.0\n"
|
||||
"t,1,1,8,9.9,0,0.0,0.0\n")
|
||||
points, err = parse_thickness_csv(path)
|
||||
assert err == ""
|
||||
assert points == [[10.0, -20.0, 1.5]]
|
||||
|
||||
|
||||
def test_parse_thickness_csv_bad_header(tmp_path):
|
||||
from pygui.backend.visualization.wafer_map_item import parse_thickness_csv
|
||||
|
||||
path = _write_csv(tmp_path, "t,1,1,7,1.5,0,10.0,-20.0\n", header="A,B,C\n")
|
||||
points, err = parse_thickness_csv(path)
|
||||
assert points == []
|
||||
assert "header" in err
|
||||
|
||||
|
||||
def test_parse_thickness_csv_malformed_value(tmp_path):
|
||||
from pygui.backend.visualization.wafer_map_item import parse_thickness_csv
|
||||
|
||||
path = _write_csv(tmp_path, "t,1,1,7,oops,0,10.0,-20.0\n")
|
||||
points, err = parse_thickness_csv(path)
|
||||
assert points == []
|
||||
assert "Malformed" in err
|
||||
|
||||
|
||||
def test_parse_thickness_csv_missing_file():
|
||||
from pygui.backend.visualization.wafer_map_item import parse_thickness_csv
|
||||
|
||||
points, err = parse_thickness_csv("/no/such/file.csv")
|
||||
assert points == []
|
||||
assert "Unable to read" in err
|
||||
|
||||
|
||||
def test_load_thickness_slot(tmp_path):
|
||||
"""loadThickness feeds parsed points into thicknessData."""
|
||||
from pygui.backend.visualization.wafer_map_item import WaferMapItem
|
||||
|
||||
item = WaferMapItem()
|
||||
path = _write_csv(tmp_path, "t,1,1,7,1.5,0,10.0,-20.0\n")
|
||||
assert item.loadThickness(path) == ""
|
||||
assert item.hasThickness is True
|
||||
|
||||
assert item.loadThickness("/no/such/file.csv") != ""
|
||||
# Failed load keeps the previously loaded data.
|
||||
assert item.hasThickness is True
|
||||
|
||||
|
||||
def test_show_thickness_setter():
|
||||
|
||||
Reference in New Issue
Block a user