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

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# 

24 

25""" 

26Generation of solver-native input files from a ``PEX25DScene``. 

27 

28The CLI exposes this operation as ``pex25d export``. 

29 

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""" 

37 

38from __future__ import annotations 

39 

40from typing import * 

41 

42from ..plugin_api.v1 import ExportError, ExporterUnavailable, PEX25DSceneExporter 

43 

44if TYPE_CHECKING: 

45 from ..plugin.exporter_registry import ExporterRegistry 

46 from klayout_pex_protobuf.kpex.pex25d.pex25d_scene_pb2 import PEX25DScene 

47 

48 

49class ExporterExecutionError(ExportError): 

50 """An exporter crashed; the original exception is preserved as the cause.""" 

51 

52 

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``. 

62 

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. 

66 

67 Pass a registry to reuse its metadata snapshot across multiple exports. 

68 Without one, installed exporters are discovered for this call. 

69 

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) 

77 

78 

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. 

88 

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 

109 

110 

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 }) 

119 

120 

121def create_fastercap_exporter() -> PEX25DSceneExporter: 

122 """FasterCap input: a list file and one geometry file per surface. 

123 

124 Constructs the exporter without geometry imports; KLayout loads on export. 

125 """ 

126 from ..fastercap.pex25d_exporter import FasterCapSceneExporter 

127 return FasterCapSceneExporter() 

128 

129 

130def create_fastcap2_exporter() -> PEX25DSceneExporter: 

131 """FastCap2 input: the FasterCap file set, with FastCap file names. 

132 

133 Constructs the exporter without geometry imports; KLayout loads on export. 

134 """ 

135 from ..fastercap.pex25d_exporter import FastCap2SceneExporter 

136 return FastCap2SceneExporter() 

137 

138 

139def create_stl_exporter() -> PEX25DSceneExporter: 

140 """STL solids of the scene, one file per dielectric and net, for viewing. 

141 

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()