from pathlib import Path from typing import cast import numpy import pytest from numpy.testing import assert_equal, assert_allclose from ..error import LibraryError from ..pattern import Pattern from ..library import Library from ..file import gdsii from ..shapes import Path as MPath, Polygon def test_gdsii_roundtrip(tmp_path: Path) -> None: lib = Library() # Simple polygon cell pat1 = Pattern() pat1.polygon((1, 0), vertices=[[0, 0], [10, 0], [10, 10], [0, 10]]) lib["poly_cell"] = pat1 # Path cell pat2 = Pattern() pat2.path((2, 5), vertices=[[0, 0], [100, 0]], width=10) lib["path_cell"] = pat2 # Cell with Ref pat3 = Pattern() pat3.ref("poly_cell", offset=(50, 50), rotation=numpy.pi / 2) lib["ref_cell"] = pat3 gds_file = tmp_path / "test.gds" gdsii.writefile(lib, gds_file, meters_per_unit=1e-9) read_lib, info = gdsii.readfile(gds_file) assert "poly_cell" in read_lib assert "path_cell" in read_lib assert "ref_cell" in read_lib # Check polygon read_poly = cast("Polygon", read_lib["poly_cell"].shapes[(1, 0)][0]) # GDSII closes polygons, so it might have an extra vertex or different order assert len(read_poly.vertices) >= 4 # Check bounds as a proxy for geometry correctness assert_equal(read_lib["poly_cell"].get_bounds(), [[0, 0], [10, 10]]) # Check path read_path = cast("MPath", read_lib["path_cell"].shapes[(2, 5)][0]) assert isinstance(read_path, MPath) assert read_path.width == 10 assert_equal(read_path.vertices, [[0, 0], [100, 0]]) # Check Ref read_ref = read_lib["ref_cell"].refs["poly_cell"][0] assert_equal(read_ref.offset, [50, 50]) assert_allclose(read_ref.rotation, numpy.pi / 2, atol=1e-5) def test_gdsii_annotations(tmp_path: Path) -> None: lib = Library() pat = Pattern() # GDS only supports integer keys in range [1, 126] for properties pat.polygon((1, 0), vertices=[[0, 0], [1, 0], [1, 1]], annotations={"1": ["hello"]}) lib["cell"] = pat gds_file = tmp_path / "test_ann.gds" gdsii.writefile(lib, gds_file, meters_per_unit=1e-9) read_lib, _ = gdsii.readfile(gds_file) read_ann = read_lib["cell"].shapes[(1, 0)][0].annotations assert read_ann is not None assert read_ann["1"] == ["hello"] def test_gdsii_check_valid_names_validates_generator_lengths() -> None: names = (name for name in ("a" * 40,)) with pytest.raises(LibraryError, match="invalid names"): gdsii.check_valid_names(names)