Coverage for klayout_pex/pex25d/exporters.py: 100%
33 statements
« prev ^ index » next coverage.py v7.17.2, created at 2026-11-06 13:14 +0000
« prev ^ index » next coverage.py v7.17.2, created at 2026-11-06 13:14 +0000
1#
2# --------------------------------------------------------------------------------
3# SPDX-FileCopyrightText: 2024-2026 Martin Jan Köhler and Harald Pretl
4# Johannes Kepler University, Institute for Integrated Circuits.
5#
6# This file is part of KPEX
7# (see https://github.com/iic-jku/klayout-pex).
8#
9# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation, either version 3 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program. If not, see <http://www.gnu.org/licenses/>.
21# SPDX-License-Identifier: GPL-3.0-or-later
22# --------------------------------------------------------------------------------
23#
25"""
26Generation of solver-native input files from a ``PEX25DScene``.
28The CLI exposes this operation as ``pex25d export``.
30Exporting is the one part of this package that is not pure format work: turning
31a scene into a solver's input needs polygon booleans and meshing, so a backend
32depends on a geometry library. Backends are therefore imported on use, and a
33missing dependency is reported rather than surfacing as an ImportError from an
34unexpected place. Reading, validating, converting and resolving stay
35dependency-free.
36"""
38from __future__ import annotations
40from typing import *
42from ..plugin_api.v1 import ExportError, ExporterUnavailable, PEX25DSceneExporter
44if TYPE_CHECKING:
45 from ..plugin.exporter_registry import ExporterRegistry
46 from klayout_pex_protobuf.kpex.pex25d.pex25d_scene_pb2 import PEX25DScene
49class ExporterExecutionError(ExportError):
50 """An exporter crashed; the original exception is preserved as the cause."""
53def export(scene: PEX25DScene,
54 target: str,
55 output_dir_path: str,
56 prefix: str = '',
57 options: Optional[Mapping[str, Any]] = None,
58 *,
59 registry: Optional[ExporterRegistry] = None) -> List[str]:
60 """
61 Export ``scene`` as native input for ``target`` into ``output_dir_path``.
63 Does not run the engine. ``target`` is an exporter entry-point name or
64 a qualified ``distribution:name``. Options are passed to the selected
65 exporter, which owns their schema and validation.
67 Pass a registry to reuse its metadata snapshot across multiple exports.
68 Without one, installed exporters are discovered for this call.
70 :return: only paths written by this call, primary input first — for FasterCap
71 the ``.lst``, its referenced surface files, and any requested STL files.
72 """
73 registry = registry if registry is not None else exporter_registry()
74 backend = registry.load(target)
75 return export_with_backend(backend, scene, target, output_dir_path,
76 prefix, options, registry=registry)
79def export_with_backend(backend: PEX25DSceneExporter,
80 scene: PEX25DScene,
81 target: str,
82 output_dir_path: str,
83 prefix: str = '',
84 options: Optional[Mapping[str, Any]] = None,
85 *,
86 registry: Optional[ExporterRegistry] = None) -> List[str]:
87 """Export with an already loaded backend, which need not be registered.
89 ``target`` identifies the backend in error messages. Only an unexpected
90 exception triggers provider lookup; a supplied registry reuses its metadata
91 snapshot for that lookup. If lookup fails, the message uses ``target``.
92 The backend is reused without another factory call. ExportError, NotImplementedError
93 and OSError pass through unchanged; unexpected exceptions become ExporterExecutionError
94 with their original cause. Return paths follow the contract of ``export``.
95 """
96 try:
97 return backend.export(scene, output_dir_path=output_dir_path, prefix=prefix, options=options)
98 except (ExportError, NotImplementedError, OSError):
99 raise
100 except Exception as exc:
101 provider = target
102 try:
103 registry = registry if registry is not None else exporter_registry()
104 provider = registry.get_info(target).qualified_name
105 except Exception:
106 pass # Metadata failures must not hide the exporter's original crash.
107 raise ExporterExecutionError(
108 f"Exporter '{provider}' crashed: {type(exc).__name__}: {exc}") from exc
111def exporter_registry() -> ExporterRegistry:
112 """Discover installed exporters alongside the built-in implementations."""
113 from ..plugin.exporter_registry import ExporterRegistry
114 return ExporterRegistry({
115 'fastercap': create_fastercap_exporter,
116 'fastcap2': create_fastcap2_exporter,
117 'stl': create_stl_exporter,
118 })
121def create_fastercap_exporter() -> PEX25DSceneExporter:
122 """FasterCap input: a list file and one geometry file per surface.
124 Constructs the exporter without geometry imports; KLayout loads on export.
125 """
126 from ..fastercap.pex25d_exporter import FasterCapSceneExporter
127 return FasterCapSceneExporter()
130def create_fastcap2_exporter() -> PEX25DSceneExporter:
131 """FastCap2 input: the FasterCap file set, with FastCap file names.
133 Constructs the exporter without geometry imports; KLayout loads on export.
134 """
135 from ..fastercap.pex25d_exporter import FastCap2SceneExporter
136 return FastCap2SceneExporter()
139def create_stl_exporter() -> PEX25DSceneExporter:
140 """STL solids of the scene, one file per dielectric and net, for viewing.
142 Constructs the exporter without geometry imports; KLayout loads on export.
143 The solids are built from the FasterCap model for now.
144 """
145 from ..stl.pex25d_exporter import STLSceneExporter
146 return STLSceneExporter()