rocket-engine 0.0.2b1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- rocket_engine/__init__.py +8 -0
- rocket_engine/__main__.py +12 -0
- rocket_engine/adapters/README.md +54 -0
- rocket_engine/adapters/__init__.py +7 -0
- rocket_engine/adapters/api.py +39 -0
- rocket_engine/adapters/base.py +46 -0
- rocket_engine/adapters/cace/__init__.py +163 -0
- rocket_engine/adapters/circulax/README.md +10 -0
- rocket_engine/adapters/circulax/__init__.py +112 -0
- rocket_engine/adapters/circulax/_driver.py +190 -0
- rocket_engine/adapters/circulax/adapter.py +538 -0
- rocket_engine/adapters/circulax/results.py +291 -0
- rocket_engine/adapters/cli/README.md +34 -0
- rocket_engine/adapters/cli/__init__.py +305 -0
- rocket_engine/adapters/connectivity/__init__.py +196 -0
- rocket_engine/adapters/connectivity/results.py +214 -0
- rocket_engine/adapters/cosim/README.md +9 -0
- rocket_engine/adapters/cosim/__init__.py +1390 -0
- rocket_engine/adapters/cosim/results.py +214 -0
- rocket_engine/adapters/devsim/__init__.py +171 -0
- rocket_engine/adapters/digital_flow/README.md +9 -0
- rocket_engine/adapters/digital_flow/__init__.py +1121 -0
- rocket_engine/adapters/digital_flow/results.py +227 -0
- rocket_engine/adapters/digital_flow/state.py +462 -0
- rocket_engine/adapters/drc/README.klayout.md +7 -0
- rocket_engine/adapters/drc/README.md +7 -0
- rocket_engine/adapters/drc/__init__.py +1 -0
- rocket_engine/adapters/drc/klayout.py +952 -0
- rocket_engine/adapters/drc/magic.py +287 -0
- rocket_engine/adapters/drc/results.py +184 -0
- rocket_engine/adapters/drc/results_kl.py +188 -0
- rocket_engine/adapters/elmer/__init__.py +163 -0
- rocket_engine/adapters/envelope.py +120 -0
- rocket_engine/adapters/equivalence/__init__.py +156 -0
- rocket_engine/adapters/errors.py +181 -0
- rocket_engine/adapters/extract_magic/README.md +15 -0
- rocket_engine/adapters/extract_magic/__init__.py +425 -0
- rocket_engine/adapters/extract_magic/results.py +209 -0
- rocket_engine/adapters/formal_sby/README.md +7 -0
- rocket_engine/adapters/formal_sby/__init__.py +773 -0
- rocket_engine/adapters/formal_sby/formal_edge.py +195 -0
- rocket_engine/adapters/formal_sby/results.py +185 -0
- rocket_engine/adapters/gdsfactory/__init__.py +194 -0
- rocket_engine/adapters/gdsfactory/_driver.py +459 -0
- rocket_engine/adapters/gdsfactory/adapter.py +609 -0
- rocket_engine/adapters/gdsfactory/results.py +181 -0
- rocket_engine/adapters/hdl_sim/README.md +7 -0
- rocket_engine/adapters/hdl_sim/__init__.py +369 -0
- rocket_engine/adapters/hdl_sim/ghdl.py +155 -0
- rocket_engine/adapters/hdl_sim/results.py +178 -0
- rocket_engine/adapters/hdl_sim/verilator.py +167 -0
- rocket_engine/adapters/http/README.md +15 -0
- rocket_engine/adapters/http/__init__.py +458 -0
- rocket_engine/adapters/http/events.py +63 -0
- rocket_engine/adapters/ipc/README.md +9 -0
- rocket_engine/adapters/ipc/__init__.py +111 -0
- rocket_engine/adapters/lvs_netgen/README.md +20 -0
- rocket_engine/adapters/lvs_netgen/__init__.py +889 -0
- rocket_engine/adapters/lvs_netgen/results.py +168 -0
- rocket_engine/adapters/mcp/README.md +19 -0
- rocket_engine/adapters/mcp/__init__.py +85 -0
- rocket_engine/adapters/mcp/api-schema.json +6107 -0
- rocket_engine/adapters/mcp/pull.py +246 -0
- rocket_engine/adapters/mcp/server.py +794 -0
- rocket_engine/adapters/meep/__init__.py +167 -0
- rocket_engine/adapters/meow/README.md +7 -0
- rocket_engine/adapters/meow/__init__.py +190 -0
- rocket_engine/adapters/meow/_driver.py +227 -0
- rocket_engine/adapters/meow/_envelope.py +108 -0
- rocket_engine/adapters/meow/adapter.py +491 -0
- rocket_engine/adapters/meow/results.py +218 -0
- rocket_engine/adapters/mutation/__init__.py +192 -0
- rocket_engine/adapters/ngspice/README.md +28 -0
- rocket_engine/adapters/ngspice/__init__.py +627 -0
- rocket_engine/adapters/ngspice/results.py +215 -0
- rocket_engine/adapters/postlayout/README.md +28 -0
- rocket_engine/adapters/postlayout/__init__.py +17 -0
- rocket_engine/adapters/postlayout/adapter.py +1062 -0
- rocket_engine/adapters/postlayout/results.py +330 -0
- rocket_engine/adapters/postlayout/translate.py +71 -0
- rocket_engine/adapters/profile.py +220 -0
- rocket_engine/adapters/sax/README.md +23 -0
- rocket_engine/adapters/sax/__init__.py +516 -0
- rocket_engine/adapters/sax/_driver.py +148 -0
- rocket_engine/adapters/sax/results.py +291 -0
- rocket_engine/adapters/stdio_console.py +1151 -0
- rocket_engine/adapters/syntax/README.md +5 -0
- rocket_engine/adapters/syntax/__init__.py +366 -0
- rocket_engine/adapters/syntax/results.py +181 -0
- rocket_engine/adapters/synth_yosys/README.md +7 -0
- rocket_engine/adapters/synth_yosys/__init__.py +655 -0
- rocket_engine/adapters/synth_yosys/amaranth.py +120 -0
- rocket_engine/adapters/synth_yosys/ghdl.py +128 -0
- rocket_engine/adapters/synth_yosys/results.py +173 -0
- rocket_engine/adapters/timing_sta/README.md +9 -0
- rocket_engine/adapters/timing_sta/__init__.py +726 -0
- rocket_engine/adapters/view_sync/__init__.py +185 -0
- rocket_engine/adapters/view_sync/results.py +189 -0
- rocket_engine/adapters/vlsir/__init__.py +142 -0
- rocket_engine/adapters/xschem/__init__.py +440 -0
- rocket_engine/adapters/xschem/deck.py +266 -0
- rocket_engine/clients/__init__.py +5 -0
- rocket_engine/clients/runtime.py +255 -0
- rocket_engine/composition.py +2279 -0
- rocket_engine/execution/README.md +30 -0
- rocket_engine/execution/__init__.py +150 -0
- rocket_engine/execution/apig/__init__.py +1 -0
- rocket_engine/execution/apig/pool.py +463 -0
- rocket_engine/execution/apig/submit.py +124 -0
- rocket_engine/execution/block_runs_scope.py +479 -0
- rocket_engine/execution/coalesce.py +414 -0
- rocket_engine/execution/console/__init__.py +1 -0
- rocket_engine/execution/console/apply_session.py +318 -0
- rocket_engine/execution/console/lifecycle.py +265 -0
- rocket_engine/execution/dispatch.py +205 -0
- rocket_engine/execution/errors.py +31 -0
- rocket_engine/execution/ports.py +797 -0
- rocket_engine/execution/pyexec/__init__.py +1 -0
- rocket_engine/execution/pyexec/apply_context.py +547 -0
- rocket_engine/execution/pyexec/approvals.py +173 -0
- rocket_engine/execution/pyexec/runner.py +404 -0
- rocket_engine/execution/pyexec/support.py +464 -0
- rocket_engine/execution/python_exec.py +897 -0
- rocket_engine/execution/queue.py +85 -0
- rocket_engine/execution/replay_safe.py +601 -0
- rocket_engine/execution/routing/__init__.py +1 -0
- rocket_engine/execution/routing/calls.py +364 -0
- rocket_engine/execution/routing/namespace.py +785 -0
- rocket_engine/execution/routing/ports.py +102 -0
- rocket_engine/execution/routing/tools.py +346 -0
- rocket_engine/execution/runner.py +311 -0
- rocket_engine/execution/runtime.py +1149 -0
- rocket_engine/execution/service.py +279 -0
- rocket_engine/execution/worker.py +464 -0
- rocket_engine/interfaces/README.md +26 -0
- rocket_engine/interfaces/__init__.py +58 -0
- rocket_engine/interfaces/apig_assets.py +407 -0
- rocket_engine/interfaces/celllink.py +461 -0
- rocket_engine/interfaces/documents.py +92 -0
- rocket_engine/interfaces/envelopes.py +131 -0
- rocket_engine/interfaces/errors.py +16 -0
- rocket_engine/interfaces/layout.py +410 -0
- rocket_engine/interfaces/layout_schema.yaml +278 -0
- rocket_engine/interfaces/paths.py +223 -0
- rocket_engine/interfaces/pdks.py +550 -0
- rocket_engine/interfaces/ports.py +72 -0
- rocket_engine/interfaces/references.py +115 -0
- rocket_engine/interfaces/refs.py +85 -0
- rocket_engine/interfaces/runparams.py +304 -0
- rocket_engine/interfaces/setup.py +552 -0
- rocket_engine/interfaces/setup_catalogue.yaml +243 -0
- rocket_engine/interfaces/setup_probes.py +66 -0
- rocket_engine/interfaces/vocabulary.py +58 -0
- rocket_engine/interfaces/yaml_dump.py +31 -0
- rocket_engine/library/README.md +22 -0
- rocket_engine/library/__init__.py +13 -0
- rocket_engine/library/apig_catalog.py +371 -0
- rocket_engine/library/catalog.py +185 -0
- rocket_engine/library/errors.py +16 -0
- rocket_engine/mutate/__init__.py +776 -0
- rocket_engine/mutate/operators.py +700 -0
- rocket_engine/ops/__init__.py +1 -0
- rocket_engine/ops/deferred.py +279 -0
- rocket_engine/ops/editors.py +404 -0
- rocket_engine/ops/evidence.py +194 -0
- rocket_engine/ops/gates.py +262 -0
- rocket_engine/ops/ports.py +76 -0
- rocket_engine/ops/queries.py +417 -0
- rocket_engine/ops/runs.py +553 -0
- rocket_engine/ops/submit.py +614 -0
- rocket_engine/project/README.md +27 -0
- rocket_engine/project/__init__.py +6 -0
- rocket_engine/project/canvas/__init__.py +55 -0
- rocket_engine/project/canvas/compile.py +109 -0
- rocket_engine/project/canvas/integrate.py +48 -0
- rocket_engine/project/canvas/schema.py +241 -0
- rocket_engine/project/canvas/templates.py +46 -0
- rocket_engine/project/canvas/validate.py +603 -0
- rocket_engine/project/edit/__init__.py +5 -0
- rocket_engine/project/edit/cas.py +87 -0
- rocket_engine/project/edit/transactions.py +282 -0
- rocket_engine/project/errors.py +16 -0
- rocket_engine/project/frontend13.py +685 -0
- rocket_engine/project/geometry/__init__.py +23 -0
- rocket_engine/project/geometry/ops.py +451 -0
- rocket_engine/project/geometry/snap.py +103 -0
- rocket_engine/project/ip/__init__.py +1 -0
- rocket_engine/project/ip/blocks.py +195 -0
- rocket_engine/project/ip/entry.schema.json +78 -0
- rocket_engine/project/ip/lifecycle.py +402 -0
- rocket_engine/project/ip/verbs.py +123 -0
- rocket_engine/project/layers/__init__.py +6 -0
- rocket_engine/project/layers/bindings.py +115 -0
- rocket_engine/project/layers/catalog.py +228 -0
- rocket_engine/project/layers/presets.py +43 -0
- rocket_engine/project/ledger/__init__.py +1 -0
- rocket_engine/project/ledger/docs.py +167 -0
- rocket_engine/project/ledger/entities.py +176 -0
- rocket_engine/project/ledger/events.py +29 -0
- rocket_engine/project/ledger/runs.py +257 -0
- rocket_engine/project/ledger/shared.py +174 -0
- rocket_engine/project/ledger/snapshots.py +385 -0
- rocket_engine/project/ledger/wires.py +552 -0
- rocket_engine/project/process/__init__.py +14 -0
- rocket_engine/project/process/model.py +193 -0
- rocket_engine/project/process/recipes.py +121 -0
- rocket_engine/project/schematic/__init__.py +1 -0
- rocket_engine/project/schematic/hierarchy.py +312 -0
- rocket_engine/project/schematic/instances.py +393 -0
- rocket_engine/project/schematic/sheets.py +198 -0
- rocket_engine/project/service.py +2941 -0
- rocket_engine/project/symbols/__init__.py +1 -0
- rocket_engine/project/symbols/cells.py +324 -0
- rocket_engine/project/symbols/linkage.py +356 -0
- rocket_engine/project/symbols/symbols.py +352 -0
- rocket_engine/project/templates/__init__.py +303 -0
- rocket_engine/project/templates/errors.py +25 -0
- rocket_engine/project/testbench/__init__.py +49 -0
- rocket_engine/project/testbench/blocks.py +619 -0
- rocket_engine/project/testbench/templates.py +134 -0
- rocket_engine/stores/README.md +12 -0
- rocket_engine/stores/__init__.py +6 -0
- rocket_engine/stores/ecs.py +1508 -0
- rocket_engine/stores/layers.py +1023 -0
- rocket_engine/stores/settings.py +1188 -0
- rocket_engine/stores/wireplace.py +1324 -0
- rocket_engine/workflows/README.md +18 -0
- rocket_engine/workflows/__init__.py +53 -0
- rocket_engine/workflows/capability_plan.py +102 -0
- rocket_engine/workflows/completion.py +228 -0
- rocket_engine/workflows/connectgraph.py +734 -0
- rocket_engine/workflows/connectgraph_emit.py +336 -0
- rocket_engine/workflows/gates.py +144 -0
- rocket_engine/workflows/photonic_wire.py +76 -0
- rocket_engine/workflows/stages.py +324 -0
- rocket_engine/workflows/viewsync.py +399 -0
- rocket_engine-0.0.2b1.dist-info/METADATA +200 -0
- rocket_engine-0.0.2b1.dist-info/RECORD +241 -0
- rocket_engine-0.0.2b1.dist-info/WHEEL +4 -0
- rocket_engine-0.0.2b1.dist-info/entry_points.txt +2 -0
- rocket_engine-0.0.2b1.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
"""Staged generate_views driver: job JSON in, result envelope JSON on stdout.
|
|
2
|
+
|
|
3
|
+
The adapter copies this file into the run workdir next to
|
|
4
|
+
`gf_views_job.json` and executes `python gf_views_driver.py
|
|
5
|
+
gf_views_job.json`. One marker-delimited JSON envelope is printed to stdout
|
|
6
|
+
(ROCKETEDA_ENVELOPE_BEGIN/END); chatter outside the markers is
|
|
7
|
+
tolerated and stays in logs.
|
|
8
|
+
|
|
9
|
+
Every recipe consumes project inputs from the job: view-spec cells +
|
|
10
|
+
params, project GDS paths, and the optional project pin map. Nothing
|
|
11
|
+
is hardcoded — the PDK, the cell list, the export filenames, and the
|
|
12
|
+
macro pin/obstruction bindings all ride the job.
|
|
13
|
+
|
|
14
|
+
Envelope: `{"ok": true, "gdsfactory_version, "result": {recipe,
|
|
15
|
+
active_pdk, cspdk_version, mappings[], artifacts[], diagnostics}}` or
|
|
16
|
+
`{"ok": false, "error": {code, message, token, line}}`. Exit 0 on
|
|
17
|
+
success, 2 on a bad cell/spec/source/format, 3 when gdsfactory or the
|
|
18
|
+
named PDK is not importable. Anything else explodes with a traceback
|
|
19
|
+
and exit 1, which parse() reports as runner_unavailable rather than
|
|
20
|
+
mistaking a tool crash for layout.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
import json
|
|
24
|
+
import sys
|
|
25
|
+
from pathlib import Path
|
|
26
|
+
|
|
27
|
+
_ENVELOPE_BEGIN = "ROCKETEDA_ENVELOPE_BEGIN"
|
|
28
|
+
_ENVELOPE_END = "ROCKETEDA_ENVELOPE_END"
|
|
29
|
+
|
|
30
|
+
_BOUNDARY_NOTE = (
|
|
31
|
+
"GDS import alone does not reconstruct macro pins/obstructions "
|
|
32
|
+
"(PRD boundary note); bind a project pin_map to publish them."
|
|
33
|
+
)
|
|
34
|
+
_BUILD_NOTE = (
|
|
35
|
+
"Cell builds carry no macro obstructions; bind a project "
|
|
36
|
+
"pin_map at import to publish them."
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _fail(code, message, token, line):
|
|
41
|
+
print(_ENVELOPE_BEGIN)
|
|
42
|
+
print(
|
|
43
|
+
json.dumps(
|
|
44
|
+
{
|
|
45
|
+
"ok": False,
|
|
46
|
+
"error": {
|
|
47
|
+
"code": code,
|
|
48
|
+
"message": message,
|
|
49
|
+
"token": token,
|
|
50
|
+
"line": line,
|
|
51
|
+
},
|
|
52
|
+
}
|
|
53
|
+
)
|
|
54
|
+
)
|
|
55
|
+
print(_ENVELOPE_END)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _find_line(text, token):
|
|
59
|
+
if not token:
|
|
60
|
+
return None
|
|
61
|
+
for number, line in enumerate((text or "").splitlines(), 1):
|
|
62
|
+
if token in line:
|
|
63
|
+
return number
|
|
64
|
+
return None
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def _polygons(comp):
|
|
68
|
+
return sum(len(polys) for polys in comp.get_polygons().values())
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def _bbox(comp):
|
|
72
|
+
box = comp.bbox()
|
|
73
|
+
return [
|
|
74
|
+
[float(box.left), float(box.bottom)],
|
|
75
|
+
[float(box.right), float(box.top)],
|
|
76
|
+
]
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _ports(comp):
|
|
80
|
+
try:
|
|
81
|
+
ports = list(comp.ports)
|
|
82
|
+
except Exception:
|
|
83
|
+
return [], []
|
|
84
|
+
names = []
|
|
85
|
+
details = []
|
|
86
|
+
for port in ports:
|
|
87
|
+
try:
|
|
88
|
+
name = port.name
|
|
89
|
+
except Exception:
|
|
90
|
+
continue
|
|
91
|
+
names.append(name)
|
|
92
|
+
try:
|
|
93
|
+
center = port.center
|
|
94
|
+
middle = [float(center[0]), float(center[1])]
|
|
95
|
+
except Exception:
|
|
96
|
+
middle = None
|
|
97
|
+
try:
|
|
98
|
+
layer = str(port.layer)
|
|
99
|
+
except Exception:
|
|
100
|
+
layer = None
|
|
101
|
+
details.append(
|
|
102
|
+
{"name": name, "center_um": middle, "layer": layer}
|
|
103
|
+
)
|
|
104
|
+
return sorted(names), details
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def _mapping(source, comp):
|
|
108
|
+
names, _ = _ports(comp)
|
|
109
|
+
return {
|
|
110
|
+
"source": source,
|
|
111
|
+
"component": comp.name,
|
|
112
|
+
"ports": names,
|
|
113
|
+
"n_polygons": _polygons(comp),
|
|
114
|
+
"bbox_um": _bbox(comp),
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def _write_json(path, payload):
|
|
119
|
+
Path(path).write_text(json.dumps(payload, indent=2), encoding="utf-8")
|
|
120
|
+
return str(Path(path).resolve())
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def _pins_artifact(comp, bound, fallback):
|
|
124
|
+
_, details = _ports(comp)
|
|
125
|
+
if bound is None:
|
|
126
|
+
return {
|
|
127
|
+
"cell": comp.name,
|
|
128
|
+
"source": fallback["source"],
|
|
129
|
+
"reconstructed": fallback["reconstructed"],
|
|
130
|
+
"boundary_note": fallback["boundary_note"],
|
|
131
|
+
"pins": details,
|
|
132
|
+
}
|
|
133
|
+
pins = [
|
|
134
|
+
{
|
|
135
|
+
"name": name,
|
|
136
|
+
"layer": dict(spec).get("layer"),
|
|
137
|
+
"x_um": dict(spec).get("x_um"),
|
|
138
|
+
"y_um": dict(spec).get("y_um"),
|
|
139
|
+
}
|
|
140
|
+
for name, spec in (bound.get("pins") or {}).items()
|
|
141
|
+
]
|
|
142
|
+
return {
|
|
143
|
+
"cell": comp.name,
|
|
144
|
+
"source": "project-pin-map",
|
|
145
|
+
"reconstructed": True,
|
|
146
|
+
"boundary_note": None,
|
|
147
|
+
"pins": pins,
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def _obstructions_artifact(comp, bound, fallback):
|
|
152
|
+
if bound is None:
|
|
153
|
+
return {
|
|
154
|
+
"cell": comp.name,
|
|
155
|
+
"source": fallback["source"],
|
|
156
|
+
"reconstructed": fallback["reconstructed"],
|
|
157
|
+
"boundary_note": fallback["boundary_note"],
|
|
158
|
+
"obstructions": [],
|
|
159
|
+
}
|
|
160
|
+
return {
|
|
161
|
+
"cell": comp.name,
|
|
162
|
+
"source": "project-pin-map",
|
|
163
|
+
"reconstructed": True,
|
|
164
|
+
"boundary_note": None,
|
|
165
|
+
"obstructions": list(bound.get("obstructions") or []),
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def _publish(comp, bound, artifacts, fallback):
|
|
170
|
+
pins_path = _write_json(
|
|
171
|
+
f"{comp.name}.pins.json",
|
|
172
|
+
_pins_artifact(comp, bound, fallback["pins"]),
|
|
173
|
+
)
|
|
174
|
+
obs_path = _write_json(
|
|
175
|
+
f"{comp.name}.obstructions.json",
|
|
176
|
+
_obstructions_artifact(comp, bound, fallback["obstructions"]),
|
|
177
|
+
)
|
|
178
|
+
artifacts.append(
|
|
179
|
+
{"kind": "pins", "cell": comp.name, "path": pins_path}
|
|
180
|
+
)
|
|
181
|
+
artifacts.append(
|
|
182
|
+
{"kind": "obstructions", "cell": comp.name, "path": obs_path}
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def _activate_cspdk(gf, cspdk_path):
|
|
187
|
+
if cspdk_path is not None:
|
|
188
|
+
root = str(Path(cspdk_path).expanduser())
|
|
189
|
+
if root not in sys.path:
|
|
190
|
+
sys.path.insert(0, root)
|
|
191
|
+
try:
|
|
192
|
+
import cspdk
|
|
193
|
+
from cspdk.si340 import activate_pdk
|
|
194
|
+
except ImportError as exc:
|
|
195
|
+
raise _MissingCspdk(str(exc)) from exc
|
|
196
|
+
activate_pdk()
|
|
197
|
+
from gdsfactory.pdk import get_active_pdk
|
|
198
|
+
|
|
199
|
+
active = get_active_pdk()
|
|
200
|
+
return active.name, getattr(cspdk, "__version__", "unknown")
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def _activate(doc, cspdk_path):
|
|
204
|
+
import gdsfactory as gf
|
|
205
|
+
|
|
206
|
+
if doc is None:
|
|
207
|
+
# Import path carries no view spec, but gf.import_gds still
|
|
208
|
+
# needs an active PDK. The project tree wins where the
|
|
209
|
+
# adapter carried it; otherwise the generic PDK keeps the
|
|
210
|
+
# read independent of build/export PDK selection.
|
|
211
|
+
if cspdk_path is not None:
|
|
212
|
+
name, version = _activate_cspdk(gf, cspdk_path)
|
|
213
|
+
return gf, name, version
|
|
214
|
+
gf.gpdk.PDK.activate()
|
|
215
|
+
return gf, "generic", None
|
|
216
|
+
pdk = doc.get("pdk", "generic")
|
|
217
|
+
if pdk == "generic":
|
|
218
|
+
gf.gpdk.PDK.activate()
|
|
219
|
+
return gf, "generic", None
|
|
220
|
+
name, version = _activate_cspdk(gf, cspdk_path)
|
|
221
|
+
return gf, name, version
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
class _MissingCspdk(Exception):
|
|
225
|
+
pass
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
def _build_cell(gf, entry):
|
|
229
|
+
from gdsfactory.pdk import get_active_pdk
|
|
230
|
+
|
|
231
|
+
active = get_active_pdk()
|
|
232
|
+
cell = entry.get("cell")
|
|
233
|
+
try:
|
|
234
|
+
factory = active.cells[cell]
|
|
235
|
+
except KeyError:
|
|
236
|
+
raise _BadCell(
|
|
237
|
+
f"Unknown cell {cell!r} in PDK {active.name!r}.", cell
|
|
238
|
+
) from None
|
|
239
|
+
params = entry.get("params") or {}
|
|
240
|
+
try:
|
|
241
|
+
return factory(**params)
|
|
242
|
+
except TypeError as exc:
|
|
243
|
+
raise _BadCell(
|
|
244
|
+
f"Bad params for cell {cell!r}: {exc}.", cell
|
|
245
|
+
) from exc
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
class _BadCell(Exception):
|
|
249
|
+
def __init__(self, message, token):
|
|
250
|
+
super().__init__(message)
|
|
251
|
+
self.token = token
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def _export_name(exports, index, component, extension):
|
|
255
|
+
if isinstance(exports, list) and index < len(exports):
|
|
256
|
+
name = (exports[index] or {}).get("filename")
|
|
257
|
+
if isinstance(name, str) and name:
|
|
258
|
+
return name
|
|
259
|
+
return f"{component}{extension}"
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
_BUILT_FALLBACK = {
|
|
263
|
+
"pins": {
|
|
264
|
+
"source": "built-ports",
|
|
265
|
+
"reconstructed": True,
|
|
266
|
+
"boundary_note": None,
|
|
267
|
+
},
|
|
268
|
+
"obstructions": {
|
|
269
|
+
"source": "built-ports",
|
|
270
|
+
"reconstructed": False,
|
|
271
|
+
"boundary_note": _BUILD_NOTE,
|
|
272
|
+
},
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
_IMPORTED_FALLBACK = {
|
|
276
|
+
"pins": {
|
|
277
|
+
"source": "gds-ports",
|
|
278
|
+
"reconstructed": False,
|
|
279
|
+
"boundary_note": _BOUNDARY_NOTE,
|
|
280
|
+
},
|
|
281
|
+
"obstructions": {
|
|
282
|
+
"source": "gds-ports",
|
|
283
|
+
"reconstructed": False,
|
|
284
|
+
"boundary_note": _BOUNDARY_NOTE,
|
|
285
|
+
},
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
def _run_build(gf, doc):
|
|
290
|
+
mappings = []
|
|
291
|
+
artifacts = []
|
|
292
|
+
for entry in doc["cells"]:
|
|
293
|
+
comp = _build_cell(gf, entry)
|
|
294
|
+
mappings.append(_mapping(entry["cell"], comp))
|
|
295
|
+
_publish(comp, None, artifacts, _BUILT_FALLBACK)
|
|
296
|
+
return mappings, artifacts, None, []
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
def _run_export(gf, doc, extension, writer):
|
|
300
|
+
mappings = []
|
|
301
|
+
artifacts = []
|
|
302
|
+
notes = []
|
|
303
|
+
matches = []
|
|
304
|
+
exports = doc.get("exports") or []
|
|
305
|
+
for index, entry in enumerate(doc["cells"]):
|
|
306
|
+
comp = _build_cell(gf, entry)
|
|
307
|
+
mappings.append(_mapping(entry["cell"], comp))
|
|
308
|
+
_publish(comp, None, artifacts, _BUILT_FALLBACK)
|
|
309
|
+
filename = _export_name(exports, index, comp.name, extension)
|
|
310
|
+
writer(comp, filename)
|
|
311
|
+
path = str(Path(filename).resolve())
|
|
312
|
+
artifacts.append(
|
|
313
|
+
{"kind": "layout", "cell": comp.name, "path": path}
|
|
314
|
+
)
|
|
315
|
+
if extension == ".gds":
|
|
316
|
+
mirror = gf.import_gds(filename)
|
|
317
|
+
match = (
|
|
318
|
+
mirror.name == comp.name
|
|
319
|
+
and _polygons(mirror) == _polygons(comp)
|
|
320
|
+
and _bbox(mirror) == _bbox(comp)
|
|
321
|
+
)
|
|
322
|
+
matches.append(match)
|
|
323
|
+
notes.append(f"readback {filename}: match={match}.")
|
|
324
|
+
else:
|
|
325
|
+
notes.append(
|
|
326
|
+
f"wrote {filename} ({Path(filename).stat().st_size} "
|
|
327
|
+
"bytes, no readback probe for oasis)."
|
|
328
|
+
)
|
|
329
|
+
roundtrip = all(matches) if matches else None
|
|
330
|
+
return mappings, artifacts, roundtrip, notes
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
def _run_import(gf, job):
|
|
334
|
+
mappings = []
|
|
335
|
+
artifacts = []
|
|
336
|
+
pin_cells = (job.get("pin_map_doc") or {}).get("cells") or {}
|
|
337
|
+
for source in job.get("gds_sources") or []:
|
|
338
|
+
try:
|
|
339
|
+
comp = gf.import_gds(source)
|
|
340
|
+
except Exception as exc:
|
|
341
|
+
raise _BadSource(
|
|
342
|
+
f"Cannot import GDS {source}: {exc}.", source
|
|
343
|
+
) from exc
|
|
344
|
+
mappings.append(_mapping(Path(source).name, comp))
|
|
345
|
+
_publish(comp, pin_cells.get(comp.name), artifacts,
|
|
346
|
+
_IMPORTED_FALLBACK)
|
|
347
|
+
if not mappings:
|
|
348
|
+
raise _BadSource("Import found no GDS sources.", None)
|
|
349
|
+
return mappings, artifacts, None, []
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
class _BadSource(Exception):
|
|
353
|
+
def __init__(self, message, token):
|
|
354
|
+
super().__init__(message)
|
|
355
|
+
self.token = token
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
def main(argv):
|
|
359
|
+
"""Run one staged views job: job JSON in, envelope on stdout.
|
|
360
|
+
|
|
361
|
+
Args:
|
|
362
|
+
argv: Argument vector; argv[1] is the staged job JSON path.
|
|
363
|
+
|
|
364
|
+
Returns:
|
|
365
|
+
Process exit code: 0 on success, 2 on a bad
|
|
366
|
+
cell/spec/source/format, 3 when gdsfactory or the named
|
|
367
|
+
PDK is not importable.
|
|
368
|
+
|
|
369
|
+
Raises:
|
|
370
|
+
ValueError: Bad recipe or bad pin-map reference (raised and
|
|
371
|
+
caught inside main into the error envelope — never
|
|
372
|
+
escapes).
|
|
373
|
+
"""
|
|
374
|
+
with open(argv[1], encoding="utf-8") as handle:
|
|
375
|
+
job = json.load(handle)
|
|
376
|
+
text = job.get("text", "")
|
|
377
|
+
doc = job.get("doc")
|
|
378
|
+
try:
|
|
379
|
+
gf, active_pdk, cspdk_ver = _activate(doc, job.get("cspdk_path"))
|
|
380
|
+
except ImportError as exc:
|
|
381
|
+
_fail(
|
|
382
|
+
"missing_dependency",
|
|
383
|
+
f"gdsfactory is not importable: {exc} "
|
|
384
|
+
"(uv sync).",
|
|
385
|
+
None,
|
|
386
|
+
None,
|
|
387
|
+
)
|
|
388
|
+
return 3
|
|
389
|
+
except _MissingCspdk as exc:
|
|
390
|
+
_fail(
|
|
391
|
+
"missing_dependency",
|
|
392
|
+
f"cspdk.si340 is not importable: {exc} "
|
|
393
|
+
"(scripts/fetch_fixtures.py --only cspdk).",
|
|
394
|
+
None,
|
|
395
|
+
None,
|
|
396
|
+
)
|
|
397
|
+
return 3
|
|
398
|
+
try:
|
|
399
|
+
recipe = job.get("recipe")
|
|
400
|
+
if recipe == "build_cells":
|
|
401
|
+
mappings, artifacts, roundtrip, notes = _run_build(gf, doc)
|
|
402
|
+
elif recipe == "export_gds":
|
|
403
|
+
mappings, artifacts, roundtrip, notes = _run_export(
|
|
404
|
+
gf, doc, ".gds", lambda comp, name: comp.write_gds(name)
|
|
405
|
+
)
|
|
406
|
+
elif recipe == "export_oasis":
|
|
407
|
+
writer = getattr(gf.Component, "write_oas", None)
|
|
408
|
+
if writer is None:
|
|
409
|
+
raise ValueError(
|
|
410
|
+
"OASIS export needs Component.write_oas, absent "
|
|
411
|
+
f"in gdsfactory {getattr(gf, '__version__', '?')}."
|
|
412
|
+
)
|
|
413
|
+
mappings, artifacts, roundtrip, notes = _run_export(
|
|
414
|
+
gf, doc, ".oas", lambda comp, name: comp.write_oas(name)
|
|
415
|
+
)
|
|
416
|
+
elif recipe == "import_gds":
|
|
417
|
+
mappings, artifacts, roundtrip, notes = _run_import(gf, job)
|
|
418
|
+
else:
|
|
419
|
+
raise ValueError(f"Unknown recipe: {recipe!r}.")
|
|
420
|
+
except _BadCell as exc:
|
|
421
|
+
_fail("invalid_cell", str(exc), exc.token,
|
|
422
|
+
_find_line(text, exc.token))
|
|
423
|
+
return 2
|
|
424
|
+
except _BadSource as exc:
|
|
425
|
+
_fail("unreadable_source", str(exc), exc.token,
|
|
426
|
+
_find_line(text, exc.token))
|
|
427
|
+
return 2
|
|
428
|
+
except ValueError as exc:
|
|
429
|
+
_fail("unsupported_format", str(exc), recipe,
|
|
430
|
+
_find_line(text, recipe))
|
|
431
|
+
return 2
|
|
432
|
+
print(_ENVELOPE_BEGIN)
|
|
433
|
+
print(
|
|
434
|
+
json.dumps(
|
|
435
|
+
{
|
|
436
|
+
"ok": True,
|
|
437
|
+
"gdsfactory_version": getattr(
|
|
438
|
+
gf, "__version__", "unknown"
|
|
439
|
+
),
|
|
440
|
+
"result": {
|
|
441
|
+
"recipe": recipe,
|
|
442
|
+
"active_pdk": active_pdk,
|
|
443
|
+
"cspdk_version": cspdk_ver,
|
|
444
|
+
"mappings": mappings,
|
|
445
|
+
"artifacts": artifacts,
|
|
446
|
+
"diagnostics": {
|
|
447
|
+
"roundtrip_match": roundtrip,
|
|
448
|
+
"notes": notes,
|
|
449
|
+
},
|
|
450
|
+
},
|
|
451
|
+
}
|
|
452
|
+
)
|
|
453
|
+
)
|
|
454
|
+
print(_ENVELOPE_END)
|
|
455
|
+
return 0
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
if __name__ == "__main__":
|
|
459
|
+
sys.exit(main(sys.argv))
|