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.
Files changed (241) hide show
  1. rocket_engine/__init__.py +8 -0
  2. rocket_engine/__main__.py +12 -0
  3. rocket_engine/adapters/README.md +54 -0
  4. rocket_engine/adapters/__init__.py +7 -0
  5. rocket_engine/adapters/api.py +39 -0
  6. rocket_engine/adapters/base.py +46 -0
  7. rocket_engine/adapters/cace/__init__.py +163 -0
  8. rocket_engine/adapters/circulax/README.md +10 -0
  9. rocket_engine/adapters/circulax/__init__.py +112 -0
  10. rocket_engine/adapters/circulax/_driver.py +190 -0
  11. rocket_engine/adapters/circulax/adapter.py +538 -0
  12. rocket_engine/adapters/circulax/results.py +291 -0
  13. rocket_engine/adapters/cli/README.md +34 -0
  14. rocket_engine/adapters/cli/__init__.py +305 -0
  15. rocket_engine/adapters/connectivity/__init__.py +196 -0
  16. rocket_engine/adapters/connectivity/results.py +214 -0
  17. rocket_engine/adapters/cosim/README.md +9 -0
  18. rocket_engine/adapters/cosim/__init__.py +1390 -0
  19. rocket_engine/adapters/cosim/results.py +214 -0
  20. rocket_engine/adapters/devsim/__init__.py +171 -0
  21. rocket_engine/adapters/digital_flow/README.md +9 -0
  22. rocket_engine/adapters/digital_flow/__init__.py +1121 -0
  23. rocket_engine/adapters/digital_flow/results.py +227 -0
  24. rocket_engine/adapters/digital_flow/state.py +462 -0
  25. rocket_engine/adapters/drc/README.klayout.md +7 -0
  26. rocket_engine/adapters/drc/README.md +7 -0
  27. rocket_engine/adapters/drc/__init__.py +1 -0
  28. rocket_engine/adapters/drc/klayout.py +952 -0
  29. rocket_engine/adapters/drc/magic.py +287 -0
  30. rocket_engine/adapters/drc/results.py +184 -0
  31. rocket_engine/adapters/drc/results_kl.py +188 -0
  32. rocket_engine/adapters/elmer/__init__.py +163 -0
  33. rocket_engine/adapters/envelope.py +120 -0
  34. rocket_engine/adapters/equivalence/__init__.py +156 -0
  35. rocket_engine/adapters/errors.py +181 -0
  36. rocket_engine/adapters/extract_magic/README.md +15 -0
  37. rocket_engine/adapters/extract_magic/__init__.py +425 -0
  38. rocket_engine/adapters/extract_magic/results.py +209 -0
  39. rocket_engine/adapters/formal_sby/README.md +7 -0
  40. rocket_engine/adapters/formal_sby/__init__.py +773 -0
  41. rocket_engine/adapters/formal_sby/formal_edge.py +195 -0
  42. rocket_engine/adapters/formal_sby/results.py +185 -0
  43. rocket_engine/adapters/gdsfactory/__init__.py +194 -0
  44. rocket_engine/adapters/gdsfactory/_driver.py +459 -0
  45. rocket_engine/adapters/gdsfactory/adapter.py +609 -0
  46. rocket_engine/adapters/gdsfactory/results.py +181 -0
  47. rocket_engine/adapters/hdl_sim/README.md +7 -0
  48. rocket_engine/adapters/hdl_sim/__init__.py +369 -0
  49. rocket_engine/adapters/hdl_sim/ghdl.py +155 -0
  50. rocket_engine/adapters/hdl_sim/results.py +178 -0
  51. rocket_engine/adapters/hdl_sim/verilator.py +167 -0
  52. rocket_engine/adapters/http/README.md +15 -0
  53. rocket_engine/adapters/http/__init__.py +458 -0
  54. rocket_engine/adapters/http/events.py +63 -0
  55. rocket_engine/adapters/ipc/README.md +9 -0
  56. rocket_engine/adapters/ipc/__init__.py +111 -0
  57. rocket_engine/adapters/lvs_netgen/README.md +20 -0
  58. rocket_engine/adapters/lvs_netgen/__init__.py +889 -0
  59. rocket_engine/adapters/lvs_netgen/results.py +168 -0
  60. rocket_engine/adapters/mcp/README.md +19 -0
  61. rocket_engine/adapters/mcp/__init__.py +85 -0
  62. rocket_engine/adapters/mcp/api-schema.json +6107 -0
  63. rocket_engine/adapters/mcp/pull.py +246 -0
  64. rocket_engine/adapters/mcp/server.py +794 -0
  65. rocket_engine/adapters/meep/__init__.py +167 -0
  66. rocket_engine/adapters/meow/README.md +7 -0
  67. rocket_engine/adapters/meow/__init__.py +190 -0
  68. rocket_engine/adapters/meow/_driver.py +227 -0
  69. rocket_engine/adapters/meow/_envelope.py +108 -0
  70. rocket_engine/adapters/meow/adapter.py +491 -0
  71. rocket_engine/adapters/meow/results.py +218 -0
  72. rocket_engine/adapters/mutation/__init__.py +192 -0
  73. rocket_engine/adapters/ngspice/README.md +28 -0
  74. rocket_engine/adapters/ngspice/__init__.py +627 -0
  75. rocket_engine/adapters/ngspice/results.py +215 -0
  76. rocket_engine/adapters/postlayout/README.md +28 -0
  77. rocket_engine/adapters/postlayout/__init__.py +17 -0
  78. rocket_engine/adapters/postlayout/adapter.py +1062 -0
  79. rocket_engine/adapters/postlayout/results.py +330 -0
  80. rocket_engine/adapters/postlayout/translate.py +71 -0
  81. rocket_engine/adapters/profile.py +220 -0
  82. rocket_engine/adapters/sax/README.md +23 -0
  83. rocket_engine/adapters/sax/__init__.py +516 -0
  84. rocket_engine/adapters/sax/_driver.py +148 -0
  85. rocket_engine/adapters/sax/results.py +291 -0
  86. rocket_engine/adapters/stdio_console.py +1151 -0
  87. rocket_engine/adapters/syntax/README.md +5 -0
  88. rocket_engine/adapters/syntax/__init__.py +366 -0
  89. rocket_engine/adapters/syntax/results.py +181 -0
  90. rocket_engine/adapters/synth_yosys/README.md +7 -0
  91. rocket_engine/adapters/synth_yosys/__init__.py +655 -0
  92. rocket_engine/adapters/synth_yosys/amaranth.py +120 -0
  93. rocket_engine/adapters/synth_yosys/ghdl.py +128 -0
  94. rocket_engine/adapters/synth_yosys/results.py +173 -0
  95. rocket_engine/adapters/timing_sta/README.md +9 -0
  96. rocket_engine/adapters/timing_sta/__init__.py +726 -0
  97. rocket_engine/adapters/view_sync/__init__.py +185 -0
  98. rocket_engine/adapters/view_sync/results.py +189 -0
  99. rocket_engine/adapters/vlsir/__init__.py +142 -0
  100. rocket_engine/adapters/xschem/__init__.py +440 -0
  101. rocket_engine/adapters/xschem/deck.py +266 -0
  102. rocket_engine/clients/__init__.py +5 -0
  103. rocket_engine/clients/runtime.py +255 -0
  104. rocket_engine/composition.py +2279 -0
  105. rocket_engine/execution/README.md +30 -0
  106. rocket_engine/execution/__init__.py +150 -0
  107. rocket_engine/execution/apig/__init__.py +1 -0
  108. rocket_engine/execution/apig/pool.py +463 -0
  109. rocket_engine/execution/apig/submit.py +124 -0
  110. rocket_engine/execution/block_runs_scope.py +479 -0
  111. rocket_engine/execution/coalesce.py +414 -0
  112. rocket_engine/execution/console/__init__.py +1 -0
  113. rocket_engine/execution/console/apply_session.py +318 -0
  114. rocket_engine/execution/console/lifecycle.py +265 -0
  115. rocket_engine/execution/dispatch.py +205 -0
  116. rocket_engine/execution/errors.py +31 -0
  117. rocket_engine/execution/ports.py +797 -0
  118. rocket_engine/execution/pyexec/__init__.py +1 -0
  119. rocket_engine/execution/pyexec/apply_context.py +547 -0
  120. rocket_engine/execution/pyexec/approvals.py +173 -0
  121. rocket_engine/execution/pyexec/runner.py +404 -0
  122. rocket_engine/execution/pyexec/support.py +464 -0
  123. rocket_engine/execution/python_exec.py +897 -0
  124. rocket_engine/execution/queue.py +85 -0
  125. rocket_engine/execution/replay_safe.py +601 -0
  126. rocket_engine/execution/routing/__init__.py +1 -0
  127. rocket_engine/execution/routing/calls.py +364 -0
  128. rocket_engine/execution/routing/namespace.py +785 -0
  129. rocket_engine/execution/routing/ports.py +102 -0
  130. rocket_engine/execution/routing/tools.py +346 -0
  131. rocket_engine/execution/runner.py +311 -0
  132. rocket_engine/execution/runtime.py +1149 -0
  133. rocket_engine/execution/service.py +279 -0
  134. rocket_engine/execution/worker.py +464 -0
  135. rocket_engine/interfaces/README.md +26 -0
  136. rocket_engine/interfaces/__init__.py +58 -0
  137. rocket_engine/interfaces/apig_assets.py +407 -0
  138. rocket_engine/interfaces/celllink.py +461 -0
  139. rocket_engine/interfaces/documents.py +92 -0
  140. rocket_engine/interfaces/envelopes.py +131 -0
  141. rocket_engine/interfaces/errors.py +16 -0
  142. rocket_engine/interfaces/layout.py +410 -0
  143. rocket_engine/interfaces/layout_schema.yaml +278 -0
  144. rocket_engine/interfaces/paths.py +223 -0
  145. rocket_engine/interfaces/pdks.py +550 -0
  146. rocket_engine/interfaces/ports.py +72 -0
  147. rocket_engine/interfaces/references.py +115 -0
  148. rocket_engine/interfaces/refs.py +85 -0
  149. rocket_engine/interfaces/runparams.py +304 -0
  150. rocket_engine/interfaces/setup.py +552 -0
  151. rocket_engine/interfaces/setup_catalogue.yaml +243 -0
  152. rocket_engine/interfaces/setup_probes.py +66 -0
  153. rocket_engine/interfaces/vocabulary.py +58 -0
  154. rocket_engine/interfaces/yaml_dump.py +31 -0
  155. rocket_engine/library/README.md +22 -0
  156. rocket_engine/library/__init__.py +13 -0
  157. rocket_engine/library/apig_catalog.py +371 -0
  158. rocket_engine/library/catalog.py +185 -0
  159. rocket_engine/library/errors.py +16 -0
  160. rocket_engine/mutate/__init__.py +776 -0
  161. rocket_engine/mutate/operators.py +700 -0
  162. rocket_engine/ops/__init__.py +1 -0
  163. rocket_engine/ops/deferred.py +279 -0
  164. rocket_engine/ops/editors.py +404 -0
  165. rocket_engine/ops/evidence.py +194 -0
  166. rocket_engine/ops/gates.py +262 -0
  167. rocket_engine/ops/ports.py +76 -0
  168. rocket_engine/ops/queries.py +417 -0
  169. rocket_engine/ops/runs.py +553 -0
  170. rocket_engine/ops/submit.py +614 -0
  171. rocket_engine/project/README.md +27 -0
  172. rocket_engine/project/__init__.py +6 -0
  173. rocket_engine/project/canvas/__init__.py +55 -0
  174. rocket_engine/project/canvas/compile.py +109 -0
  175. rocket_engine/project/canvas/integrate.py +48 -0
  176. rocket_engine/project/canvas/schema.py +241 -0
  177. rocket_engine/project/canvas/templates.py +46 -0
  178. rocket_engine/project/canvas/validate.py +603 -0
  179. rocket_engine/project/edit/__init__.py +5 -0
  180. rocket_engine/project/edit/cas.py +87 -0
  181. rocket_engine/project/edit/transactions.py +282 -0
  182. rocket_engine/project/errors.py +16 -0
  183. rocket_engine/project/frontend13.py +685 -0
  184. rocket_engine/project/geometry/__init__.py +23 -0
  185. rocket_engine/project/geometry/ops.py +451 -0
  186. rocket_engine/project/geometry/snap.py +103 -0
  187. rocket_engine/project/ip/__init__.py +1 -0
  188. rocket_engine/project/ip/blocks.py +195 -0
  189. rocket_engine/project/ip/entry.schema.json +78 -0
  190. rocket_engine/project/ip/lifecycle.py +402 -0
  191. rocket_engine/project/ip/verbs.py +123 -0
  192. rocket_engine/project/layers/__init__.py +6 -0
  193. rocket_engine/project/layers/bindings.py +115 -0
  194. rocket_engine/project/layers/catalog.py +228 -0
  195. rocket_engine/project/layers/presets.py +43 -0
  196. rocket_engine/project/ledger/__init__.py +1 -0
  197. rocket_engine/project/ledger/docs.py +167 -0
  198. rocket_engine/project/ledger/entities.py +176 -0
  199. rocket_engine/project/ledger/events.py +29 -0
  200. rocket_engine/project/ledger/runs.py +257 -0
  201. rocket_engine/project/ledger/shared.py +174 -0
  202. rocket_engine/project/ledger/snapshots.py +385 -0
  203. rocket_engine/project/ledger/wires.py +552 -0
  204. rocket_engine/project/process/__init__.py +14 -0
  205. rocket_engine/project/process/model.py +193 -0
  206. rocket_engine/project/process/recipes.py +121 -0
  207. rocket_engine/project/schematic/__init__.py +1 -0
  208. rocket_engine/project/schematic/hierarchy.py +312 -0
  209. rocket_engine/project/schematic/instances.py +393 -0
  210. rocket_engine/project/schematic/sheets.py +198 -0
  211. rocket_engine/project/service.py +2941 -0
  212. rocket_engine/project/symbols/__init__.py +1 -0
  213. rocket_engine/project/symbols/cells.py +324 -0
  214. rocket_engine/project/symbols/linkage.py +356 -0
  215. rocket_engine/project/symbols/symbols.py +352 -0
  216. rocket_engine/project/templates/__init__.py +303 -0
  217. rocket_engine/project/templates/errors.py +25 -0
  218. rocket_engine/project/testbench/__init__.py +49 -0
  219. rocket_engine/project/testbench/blocks.py +619 -0
  220. rocket_engine/project/testbench/templates.py +134 -0
  221. rocket_engine/stores/README.md +12 -0
  222. rocket_engine/stores/__init__.py +6 -0
  223. rocket_engine/stores/ecs.py +1508 -0
  224. rocket_engine/stores/layers.py +1023 -0
  225. rocket_engine/stores/settings.py +1188 -0
  226. rocket_engine/stores/wireplace.py +1324 -0
  227. rocket_engine/workflows/README.md +18 -0
  228. rocket_engine/workflows/__init__.py +53 -0
  229. rocket_engine/workflows/capability_plan.py +102 -0
  230. rocket_engine/workflows/completion.py +228 -0
  231. rocket_engine/workflows/connectgraph.py +734 -0
  232. rocket_engine/workflows/connectgraph_emit.py +336 -0
  233. rocket_engine/workflows/gates.py +144 -0
  234. rocket_engine/workflows/photonic_wire.py +76 -0
  235. rocket_engine/workflows/stages.py +324 -0
  236. rocket_engine/workflows/viewsync.py +399 -0
  237. rocket_engine-0.0.2b1.dist-info/METADATA +200 -0
  238. rocket_engine-0.0.2b1.dist-info/RECORD +241 -0
  239. rocket_engine-0.0.2b1.dist-info/WHEEL +4 -0
  240. rocket_engine-0.0.2b1.dist-info/entry_points.txt +2 -0
  241. rocket_engine-0.0.2b1.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,282 @@
1
+ """Atomic typed edit transactions with alias resolution.
2
+
3
+ One transaction is a list of entity changes applied as a group:
4
+ alias-based creation resolves LocalRef-style "$alias" references
5
+ before persistence, every change validates CAS before anything
6
+ lands, and a failed late change rolls back the earlier ones so
7
+ the ledger never keeps a partial batch.
8
+ """
9
+
10
+ try:
11
+ from .cas import read_entity_revision
12
+ except ImportError: # pragma: no cover - standalone spec loading
13
+ import importlib.util as _ilu
14
+ from pathlib import Path as _Path
15
+
16
+ _spec = _ilu.spec_from_file_location(
17
+ "edit_cas_sibling", _Path(__file__).with_name("cas.py"))
18
+ _cas = _ilu.module_from_spec(_spec)
19
+ _spec.loader.exec_module(_cas)
20
+ read_entity_revision = _cas.read_entity_revision
21
+
22
+ _CREATES = ("create",)
23
+ _WRITES = ("set", "attach", "detach", "delete")
24
+
25
+
26
+ def _live(service, entity):
27
+ """Read the live entity revision an unnamed write may build on.
28
+
29
+ Args:
30
+ service: ProjectService handle to read through.
31
+ entity: Entity id to inspect.
32
+
33
+ Returns:
34
+ Live entity revision for the gate.
35
+ """
36
+ return read_entity_revision(service, entity)
37
+
38
+
39
+ def _resolve(value, aliases):
40
+ """Resolve one alias reference to its minted entity id.
41
+
42
+ Args:
43
+ value: Candidate entity id or "$alias" reference.
44
+ aliases: Mapping of alias name to minted entity id.
45
+
46
+ Returns:
47
+ Minted entity id for known aliases, else the value.
48
+
49
+ Raises:
50
+ ValueError: For an alias with no minted entity yet.
51
+ """
52
+ if isinstance(value, str) and value.startswith("$"):
53
+ name = value[1:]
54
+ if name not in aliases:
55
+ error = ValueError(f"Unknown alias reference: {value}.")
56
+ error.code = "invalid_ref"
57
+ raise error
58
+ return aliases[name]
59
+ return value
60
+
61
+
62
+ def _validate_change(change):
63
+ """Check one change dict carries its required keys.
64
+
65
+ Args:
66
+ change: Change mapping with an op discriminator.
67
+
68
+ Returns:
69
+ The op string of the change.
70
+
71
+ Raises:
72
+ ValueError: invalid_command naming the missing field.
73
+ """
74
+ op = change.get("op")
75
+ if op in _CREATES:
76
+ return op
77
+ if op not in _WRITES:
78
+ error = ValueError(f"Unknown change op: {op!r}.")
79
+ error.code = "invalid_command"
80
+ raise error
81
+ if "entity" not in change:
82
+ error = ValueError("Change is missing its entity.")
83
+ error.code = "invalid_command"
84
+ raise error
85
+ if op in ("set", "attach") and (
86
+ "component" not in change or "data" not in change
87
+ ):
88
+ error = ValueError("Set/attach needs component and data.")
89
+ error.code = "invalid_command"
90
+ raise error
91
+ if op == "detach" and "component" not in change:
92
+ error = ValueError("Detach needs a component.")
93
+ error.code = "invalid_command"
94
+ raise error
95
+ return op
96
+
97
+
98
+ def apply_transaction(service, request_id, command_text, changes,
99
+ expected_revision=None):
100
+ """Apply one batch of entity changes atomically.
101
+
102
+ Args:
103
+ service: ProjectService handle to write through.
104
+ request_id: Client envelope id; sub-envelopes derive
105
+ from it so replays stay idempotent.
106
+ command_text: Command text for identity comparison.
107
+ changes: List of change mappings (create with optional
108
+ alias, set, attach, detach, delete). Set/attach
109
+ may name expected_entity_revision for CAS; create
110
+ steps mint engine ids and register their alias.
111
+ expected_revision: Global head the batch was read at;
112
+ None skips the head gate for pure CAS batches.
113
+
114
+ Returns:
115
+ Receipt with request id, applied count, minted entity
116
+ ids, alias mapping, and revision transition.
117
+
118
+ Raises:
119
+ Exception: The first failing change error after rolling
120
+ back earlier changes (revision_conflict,
121
+ unknown_entity, invalid_ref, or invalid_command).
122
+
123
+ Caution: Rollback writes compensating revisions, so the
124
+ head advances even when the batch fails — history stays
125
+ append-only, never rewritten.
126
+ """
127
+ for change in changes:
128
+ _validate_change(change)
129
+ revision_from = service.snapshot()["current_revision"]
130
+ if expected_revision is not None:
131
+ head = service.snapshot()["current_revision"]
132
+ if head != expected_revision:
133
+ pure_cas = all(
134
+ change.get("expected_entity_revision") is not None
135
+ for change in changes
136
+ if change.get("op") in _WRITES
137
+ )
138
+ if not (pure_cas and changes):
139
+ error = ValueError(
140
+ f"Stale head {expected_revision}, live {head}."
141
+ )
142
+ error.code = "revision_conflict"
143
+ raise error
144
+ aliases = {}
145
+ minted = []
146
+ undo = []
147
+ applied = 0
148
+ try:
149
+ for index, change in enumerate(changes):
150
+ sub_id = f"{request_id}:txn:{index}"
151
+ sub_text = f"{command_text} [{index}]"
152
+ op = change["op"]
153
+ if op == "create":
154
+ created = service.create_entity(
155
+ sub_id, sub_text,
156
+ kind=change.get("kind", ""),
157
+ components=dict(change.get("components", {})),
158
+ )
159
+ entity = created["entity"]
160
+ minted.append(entity)
161
+ if "alias" in change:
162
+ aliases[change["alias"]] = entity
163
+ undo.append(("delete", entity))
164
+ applied += 1
165
+ continue
166
+ entity = _resolve(change["entity"], aliases)
167
+ named = change.get("expected_entity_revision")
168
+ if named is not None:
169
+ live = read_entity_revision(service, entity)
170
+ if live != named:
171
+ error = ValueError(
172
+ f"Entity {entity} at revision {live}, "
173
+ f"writer expected {named}.",
174
+ )
175
+ error.code = "revision_conflict"
176
+ raise error
177
+ expected = named
178
+ else:
179
+ try:
180
+ expected = _live(service, entity)
181
+ except Exception:
182
+ expected = None
183
+ if op == "set":
184
+ try:
185
+ prior = service.get_component(
186
+ entity, change["component"])["data"]
187
+ except Exception:
188
+ prior = None
189
+ service.set_component(
190
+ entity, change["component"], change["data"],
191
+ sub_id, sub_text,
192
+ expected_revision=None,
193
+ expected_entity_revision=expected,
194
+ )
195
+ undo.append(
196
+ ("restore", entity, change["component"], prior))
197
+ elif op == "attach":
198
+ service.attach_component(
199
+ entity, change["component"], change["data"],
200
+ sub_id, sub_text,
201
+ expected_revision=None,
202
+ expected_entity_revision=expected,
203
+ )
204
+ undo.append(
205
+ ("detach", entity, change["component"]))
206
+ elif op == "detach":
207
+ prior = service.get_component(
208
+ entity, change["component"])["data"]
209
+ service.detach_component(
210
+ entity, change["component"], sub_id,
211
+ sub_text, expected_revision=None,
212
+ expected_entity_revision=expected,
213
+ )
214
+ undo.append(
215
+ ("restore", entity, change["component"], prior))
216
+ elif op == "delete":
217
+ service.delete_entity(
218
+ entity, sub_id, sub_text,
219
+ expected_revision=None,
220
+ expected_entity_revision=expected,
221
+ )
222
+ undo.append(("deleted", entity))
223
+ applied += 1
224
+ except Exception:
225
+ for step in reversed(undo):
226
+ try:
227
+ if step[0] == "delete":
228
+ try:
229
+ gate = _live(service, step[1])
230
+ except Exception:
231
+ gate = None
232
+ service.delete_entity(
233
+ step[1], f"{request_id}:undo:{step[1]}",
234
+ "transaction rollback",
235
+ expected_entity_revision=gate,
236
+ )
237
+ elif step[0] == "detach":
238
+ try:
239
+ gate = _live(service, step[1])
240
+ except Exception:
241
+ gate = None
242
+ service.detach_component(
243
+ step[1], step[2],
244
+ f"{request_id}:undo:{step[1]}:{step[2]}",
245
+ "transaction rollback",
246
+ expected_entity_revision=gate,
247
+ )
248
+ elif step[0] == "restore":
249
+ _, entity, component, prior = step
250
+ try:
251
+ gate = _live(service, entity)
252
+ except Exception:
253
+ gate = None
254
+ if prior is None:
255
+ try:
256
+ service.detach_component(
257
+ entity, component,
258
+ f"{request_id}:undo:{entity}:{component}",
259
+ "transaction rollback",
260
+ expected_entity_revision=gate,
261
+ )
262
+ except Exception:
263
+ pass
264
+ else:
265
+ service.set_component(
266
+ entity, component, prior,
267
+ f"{request_id}:undo:{entity}:{component}",
268
+ "transaction rollback",
269
+ expected_entity_revision=gate,
270
+ )
271
+ except Exception:
272
+ pass
273
+ raise
274
+ revision_to = service.snapshot()["current_revision"]
275
+ return {
276
+ "aliases": dict(aliases),
277
+ "applied": applied,
278
+ "entities": list(minted),
279
+ "request_id": request_id,
280
+ "revision_from": revision_from,
281
+ "revision_to": revision_to,
282
+ }
@@ -0,0 +1,16 @@
1
+ """Error type for project-service violations. Carries a stable machine code."""
2
+
3
+
4
+ class ProjectError(Exception):
5
+ """Project-service violation with a stable machine code.
6
+
7
+ Args:
8
+ code: Stable machine-readable error code.
9
+ message: Human-readable detail.
10
+ fields: Itemized fields, when the error names any.
11
+ """
12
+
13
+ def __init__(self, code, message, fields=None):
14
+ super().__init__(message)
15
+ self.code = code
16
+ self.fields = fields or []