[file.gdsii] rework gdsii module hierarchy

This commit is contained in:
Jan Petykiewicz 2026-07-09 13:40:58 -07:00
commit 088c37e9d2
14 changed files with 72 additions and 59 deletions

View file

@ -1,4 +1,4 @@
from masque.file.gdsii_perf import main
from masque.file.gdsii.perf import main
if __name__ == '__main__':

View file

@ -12,7 +12,7 @@ from masque import LibraryError
READERS: dict[str, tuple[str, tuple[str, ...]]] = {
'gdsii': ('masque.file.gdsii', ('readfile',)),
'gdsii_arrow': ('masque.file.gdsii_arrow', ('readfile', 'arrow_import', 'arrow_convert')),
'gdsii_arrow': ('masque.file.gdsii.arrow', ('readfile', 'arrow_import', 'arrow_convert')),
}

View file

@ -13,7 +13,7 @@ from pprint import pformat
from masque import BuildLibrary, Pather, Pattern, cell
from masque.file.gdsii import writefile
from masque.file.gdsii_lazy import readfile
from masque.file.gdsii.lazy import readfile
import basic_shapes
import devices

View file

@ -0,0 +1,10 @@
"""
GDSII file format readers and writers.
"""
from .klamath import check_valid_names as check_valid_names
from .klamath import read as read
from .klamath import read_elements as read_elements
from .klamath import readfile as readfile
from .klamath import rint_cast as rint_cast
from .klamath import write as write
from .klamath import writefile as writefile

View file

@ -43,12 +43,12 @@ from numpy.typing import ArrayLike, NDArray
import pyarrow
from pyarrow.cffi import ffi
from .utils import is_gzipped, tmpfile
from .. import Pattern, Ref, PatternError, LibraryError, Label, Shape
from ..shapes import Polygon, Path, PolyCollection, RectCollection
from ..repetition import Grid
from ..utils import layer_t, annotations_t
from ..library import LazyLibrary, Library, ILibrary, ILibraryView
from ..utils import is_gzipped, tmpfile
from ... import Pattern, Ref, PatternError, LibraryError, Label, Shape
from ...shapes import Polygon, Path, PolyCollection, RectCollection
from ...repetition import Grid
from ...utils import layer_t, annotations_t
from ...library import LazyLibrary, Library, ILibrary, ILibraryView
logger = logging.getLogger(__name__)
@ -136,7 +136,7 @@ def _installed_library_candidates() -> list[pathlib.Path]:
def _repo_library_candidates() -> list[pathlib.Path]:
repo_root = pathlib.Path(__file__).resolve().parents[2]
repo_root = pathlib.Path(__file__).resolve().parents[3]
library_name = _local_library_filename()
return [
repo_root / 'klamath-rs' / 'target' / 'release' / library_name,
@ -167,7 +167,7 @@ def is_available() -> bool:
def _get_clib() -> Any:
global clib
global clib # noqa: PLW0603
if clib is None:
lib_path = find_klamath_rs_library()
if lib_path is None:

View file

@ -33,12 +33,12 @@ from numpy.typing import ArrayLike, NDArray
import klamath
from klamath import records
from .utils import is_gzipped, tmpfile
from .. import Pattern, Ref, PatternError, LibraryError, Label, Shape
from ..shapes import Polygon, Path, RectCollection
from ..repetition import Grid
from ..utils import layer_t, annotations_t
from ..library import Library, ILibrary
from ..utils import is_gzipped, tmpfile
from ... import Pattern, Ref, PatternError, LibraryError, Label, Shape
from ...shapes import Polygon, Path, RectCollection
from ...repetition import Grid
from ...utils import layer_t, annotations_t
from ...library import Library, ILibrary
logger = logging.getLogger(__name__)

View file

@ -10,7 +10,7 @@ This module provides the non-Arrow half of Masque's lazy GDS architecture:
- the source can be wrapped in `PortsLibraryView` or merged through
`OverlayLibrary`
The public surface intentionally parallels `gdsii_lazy_arrow` closely so that
The public surface intentionally parallels `gdsii.lazy_arrow` closely so that
callers can swap between the classic and Arrow-backed implementations with
minimal changes.
"""
@ -29,24 +29,24 @@ import klamath
import numpy
from klamath import records
from . import gdsii
from .utils import is_gzipped
from .gdsii_lazy_core import write as write, writefile as writefile
from ..error import LibraryError
from ..library import (
from . import klamath as gdsii
from .lazy_write import write as write, writefile as writefile
from ..utils import is_gzipped
from ...error import LibraryError
from ...library import (
ILibraryView,
LibraryView,
PortsLibraryView,
dangling_mode_t,
)
from ..utils import apply_transforms
from ...utils import apply_transforms
if TYPE_CHECKING:
from collections.abc import Iterator, Sequence
from numpy.typing import NDArray
from ..pattern import Pattern
from ...pattern import Pattern
logger = logging.getLogger(__name__)

View file

@ -1,7 +1,7 @@
"""
Lazy GDSII readers and writers backed by native Arrow scan/materialize paths.
This module is intentionally separate from `gdsii_arrow` so the eager read path
This module is intentionally separate from `gdsii.arrow` so the eager read path
keeps its current behavior and performance profile.
"""
from __future__ import annotations
@ -16,16 +16,16 @@ import pathlib
import numpy
from . import gdsii_arrow
from .utils import is_gzipped
from .gdsii_lazy_core import write as write, writefile as writefile
from ..library import (
from . import arrow
from .lazy_write import write as write, writefile as writefile
from ..utils import is_gzipped
from ...library import (
ILibraryView,
LibraryView,
PortsLibraryView,
dangling_mode_t,
)
from ..utils import apply_transforms
from ...utils import apply_transforms
if TYPE_CHECKING:
from collections.abc import Iterator, Sequence
@ -33,7 +33,7 @@ if TYPE_CHECKING:
from numpy.typing import NDArray
import pyarrow
from ..pattern import Pattern
from ...pattern import Pattern
logger = logging.getLogger(__name__)
@ -87,11 +87,11 @@ class _ScanPayload:
refs: _ScanRefs
def is_available() -> bool:
return gdsii_arrow.is_available()
return arrow.is_available()
def _read_header(libarr: pyarrow.StructScalar) -> dict[str, Any]:
return gdsii_arrow._read_header(libarr)
return arrow._read_header(libarr)
def _open_source_buffer(path: pathlib.Path) -> _SourceBuffer:
@ -119,10 +119,10 @@ def _extract_scan_payload(libarr: pyarrow.StructScalar) -> _ScanPayload:
ref_values = refs.values
ref_offsets = refs.offsets.to_numpy()
targets = ref_values.field('target').to_numpy()
xy = gdsii_arrow._packed_xy_u64_to_pairs(ref_values.field('xy').to_numpy())
xy0 = gdsii_arrow._packed_xy_u64_to_pairs(ref_values.field('xy0').to_numpy())
xy1 = gdsii_arrow._packed_xy_u64_to_pairs(ref_values.field('xy1').to_numpy())
counts = gdsii_arrow._packed_counts_u32_to_pairs(ref_values.field('counts').to_numpy())
xy = arrow._packed_xy_u64_to_pairs(ref_values.field('xy').to_numpy())
xy0 = arrow._packed_xy_u64_to_pairs(ref_values.field('xy0').to_numpy())
xy1 = arrow._packed_xy_u64_to_pairs(ref_values.field('xy1').to_numpy())
counts = arrow._packed_counts_u32_to_pairs(ref_values.field('counts').to_numpy())
invert_y = ref_values.field('invert_y').to_numpy(zero_copy_only=False)
angle_rad = ref_values.field('angle_rad').to_numpy()
scale = ref_values.field('scale').to_numpy()
@ -228,7 +228,7 @@ class ArrowLibrary(ILibraryView):
def from_file(cls, filename: str | pathlib.Path) -> ArrowLibrary:
path = pathlib.Path(filename).expanduser().resolve()
source = _open_source_buffer(path)
scan_arr = gdsii_arrow._scan_buffer_to_arrow(source.data)
scan_arr = arrow._scan_buffer_to_arrow(source.data)
assert len(scan_arr) == 1
payload = _extract_scan_payload(scan_arr[0])
return cls(path=path, payload=payload, source=source)
@ -288,9 +288,9 @@ class ArrowLibrary(ILibraryView):
],
dtype=numpy.uint64,
)
arrow_arr = gdsii_arrow._read_selected_cells_to_arrow(self._source.data, ranges)
arrow_arr = arrow._read_selected_cells_to_arrow(self._source.data, ranges)
assert len(arrow_arr) == 1
selected_lib, _info = gdsii_arrow.read_arrow(arrow_arr[0])
selected_lib, _info = arrow.read_arrow(arrow_arr[0])
for name in uncached:
pat = selected_lib[name]
materialized[name] = pat

View file

@ -15,16 +15,16 @@ import pathlib
import klamath
from . import gdsii
from .utils import tmpfile
from ..error import LibraryError
from ..library import ILibraryView, OverlayLibrary
from ..library.overlay import _SourceEntry, _materialize_detached_pattern
from . import klamath as gdsii
from ..utils import tmpfile
from ...error import LibraryError
from ...library import ILibraryView, OverlayLibrary
from ...library.overlay import _SourceEntry, _materialize_detached_pattern
if TYPE_CHECKING:
from collections.abc import Iterator, Mapping
from ..pattern import Pattern
from ...pattern import Pattern
logger = logging.getLogger(__name__)

View file

@ -244,7 +244,7 @@ def _annotation(index: int) -> dict[int, bytes]:
return {1: f'perf-{index}'.encode('ASCII')}
def _make_box_cell(name: str, index: int, cfg: FixturePreset) -> list[elements.Element]:
def _make_box_cell(index: int, cfg: FixturePreset) -> list[elements.Element]:
cell_elements: list[elements.Element] = []
xbase = (index % 17) * 600
ybase = (index // 17) * 180
@ -277,7 +277,7 @@ def _make_box_cell(name: str, index: int, cfg: FixturePreset) -> list[elements.E
return cell_elements
def _make_poly_cell(name: str, index: int, cfg: FixturePreset) -> list[elements.Element]:
def _make_poly_cell(index: int, cfg: FixturePreset) -> list[elements.Element]:
cell_elements: list[elements.Element] = []
xbase = (index % 19) * 900
ybase = (index // 19) * 260
@ -368,12 +368,12 @@ def _poly_cluster_name(index: int) -> str:
def _write_box_cells(stream: Any, cfg: FixturePreset) -> None:
for idx in range(cfg.box_cells):
_write_struct(stream, _box_name(idx), _make_box_cell(_box_name(idx), idx, cfg))
_write_struct(stream, _box_name(idx), _make_box_cell(idx, cfg))
def _write_poly_cells(stream: Any, cfg: FixturePreset) -> None:
for idx in range(cfg.poly_cells):
_write_struct(stream, _poly_name(idx), _make_poly_cell(_poly_name(idx), idx, cfg))
_write_struct(stream, _poly_name(idx), _make_poly_cell(idx, cfg))
def _write_wrappers(stream: Any, cfg: FixturePreset) -> None:

View file

@ -14,8 +14,9 @@ from ..library import Library
from ..pattern import Pattern
from ..repetition import Grid
from ..shapes import Path as MPath, Polygon, PolyCollection, RectCollection
from ..file import gdsii, gdsii_arrow
from ..file.gdsii_perf import write_fixture
from ..file import gdsii
from ..file.gdsii import arrow as gdsii_arrow
from ..file.gdsii.perf import write_fixture
if not gdsii_arrow.is_available():
@ -267,7 +268,7 @@ def test_gdsii_arrow_invalid_input_raises_klamath_error(tmp_path: Path) -> None:
gds_file.write_bytes(b'not-a-gds')
script = textwrap.dedent(f"""
from masque.file import gdsii_arrow
from masque.file.gdsii import arrow as gdsii_arrow
try:
gdsii_arrow.readfile({str(gds_file)!r})
except Exception as exc:

View file

@ -4,7 +4,8 @@ import numpy
import pytest
from numpy.testing import assert_allclose
from ..file import gdsii, gdsii_lazy
from ..file import gdsii
from ..file.gdsii import lazy as gdsii_lazy
from ..pattern import Pattern
from ..library import Library, OverlayLibrary

View file

@ -13,8 +13,9 @@ from .. import PatternError
from ..library import Library, OverlayLibrary
from ..pattern import Pattern
from ..repetition import Grid
from ..file import gdsii, gdsii_lazy_arrow
from ..file.gdsii_perf import write_fixture
from ..file import gdsii
from ..file.gdsii import lazy_arrow as gdsii_lazy_arrow
from ..file.gdsii.perf import write_fixture
if not gdsii_lazy_arrow.is_available():
@ -177,7 +178,7 @@ def test_gdsii_lazy_arrow_invalid_input_raises_klamath_error(tmp_path: Path) ->
gds_file.write_bytes(b'not-a-gds')
script = textwrap.dedent(f"""
from masque.file import gdsii_lazy_arrow
from masque.file.gdsii import lazy_arrow as gdsii_lazy_arrow
try:
gdsii_lazy_arrow.readfile({str(gds_file)!r})
except Exception as exc:

View file

@ -3,7 +3,7 @@ import json
from pathlib import Path
from ..file import gdsii
from ..file.gdsii_perf import fixture_manifest, write_fixture
from ..file.gdsii.perf import fixture_manifest, write_fixture
def test_gdsii_perf_fixture_smoke(tmp_path: Path) -> None: