speclogician 0.0.0b1__py3-none-any.whl → 0.0.0.dev1__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 (153) hide show
  1. speclogician/agent/funcs.py +29 -0
  2. speclogician/cmd/agent_cmd.py +89 -0
  3. speclogician/cmd/data_cmd.py +24 -0
  4. speclogician/cmd/model_cmd.py +42 -0
  5. speclogician/cmd/overlay_cmd.py +30 -0
  6. speclogician/cmd/scenario_cmd.py +61 -0
  7. speclogician/cmd/state_cmd.py +52 -0
  8. speclogician/data/artifact.py +8 -50
  9. speclogician/data/container.py +18 -384
  10. speclogician/data/mapping.py +18 -17
  11. speclogician/data/refs.py +12 -11
  12. speclogician/data/reports.py +11 -0
  13. speclogician/data/traces.py +15 -6
  14. speclogician/llms/llmtools.py +102 -0
  15. speclogician/llms/overlay.py +264 -0
  16. speclogician/main.py +36 -102
  17. speclogician/modeling/__init__.py +0 -31
  18. speclogician/modeling/component.py +4 -60
  19. speclogician/modeling/conflict.py +5 -19
  20. speclogician/modeling/domain.py +93 -280
  21. speclogician/modeling/model.py +206 -0
  22. speclogician/modeling/predicates.py +20 -22
  23. speclogician/modeling/report.py +33 -0
  24. speclogician/modeling/scenario.py +119 -87
  25. speclogician/sl_cmd.py +76 -0
  26. speclogician/state/change.py +98 -378
  27. speclogician/state/state.py +183 -399
  28. speclogician/tui/box.tcss +10 -0
  29. speclogician/tui/tui.py +131 -0
  30. speclogician/utils/__init__.py +1 -70
  31. speclogician/utils/imx.py +195 -0
  32. speclogician/utils/load.py +25 -147
  33. speclogician/utils/prompt.md +1 -325
  34. speclogician-0.0.0.dev1.dist-info/METADATA +21 -0
  35. speclogician-0.0.0.dev1.dist-info/RECORD +43 -0
  36. speclogician/commands/__init__.py +0 -15
  37. speclogician/commands/cmd_ch.py +0 -616
  38. speclogician/commands/cmd_find.py +0 -256
  39. speclogician/commands/cmd_view.py +0 -202
  40. speclogician/commands/runner.py +0 -149
  41. speclogician/commands/utils.py +0 -101
  42. speclogician/demos/.DS_Store +0 -0
  43. speclogician/demos/cmd_demo.py +0 -278
  44. speclogician/demos/loader.py +0 -135
  45. speclogician/demos/model.py +0 -27
  46. speclogician/demos/runner.py +0 -51
  47. speclogician/logic/__init__.py +0 -11
  48. speclogician/logic/api/__init__.py +0 -29
  49. speclogician/logic/api/client.py +0 -606
  50. speclogician/logic/api/decomp.py +0 -67
  51. speclogician/logic/api/scenario.py +0 -102
  52. speclogician/logic/api/traces.py +0 -59
  53. speclogician/logic/lib/__init__.py +0 -19
  54. speclogician/logic/lib/complement.py +0 -107
  55. speclogician/logic/lib/domain_model.py +0 -59
  56. speclogician/logic/lib/predicates.py +0 -151
  57. speclogician/logic/lib/scenarios.py +0 -369
  58. speclogician/logic/lib/traces.py +0 -114
  59. speclogician/logic/lib/transitions.py +0 -104
  60. speclogician/logic/main.py +0 -246
  61. speclogician/logic/strings.py +0 -194
  62. speclogician/logic/utils.py +0 -135
  63. speclogician/modeling/complement.py +0 -104
  64. speclogician/modeling/spec.py +0 -306
  65. speclogician/modeling/spec_stats.py +0 -39
  66. speclogician/presentation/api.py +0 -244
  67. speclogician/presentation/builders/_links.py +0 -44
  68. speclogician/presentation/builders/container.py +0 -53
  69. speclogician/presentation/builders/data_artifact.py +0 -42
  70. speclogician/presentation/builders/domain.py +0 -54
  71. speclogician/presentation/builders/instances_list.py +0 -38
  72. speclogician/presentation/builders/predicate.py +0 -51
  73. speclogician/presentation/builders/recommendations.py +0 -41
  74. speclogician/presentation/builders/scenario.py +0 -41
  75. speclogician/presentation/builders/scenario_complement.py +0 -82
  76. speclogician/presentation/builders/smart_find.py +0 -39
  77. speclogician/presentation/builders/spec.py +0 -39
  78. speclogician/presentation/builders/state_diff.py +0 -150
  79. speclogician/presentation/builders/state_instance.py +0 -42
  80. speclogician/presentation/builders/state_instance_summary.py +0 -84
  81. speclogician/presentation/builders/trace.py +0 -58
  82. speclogician/presentation/ctx.py +0 -38
  83. speclogician/presentation/models/container.py +0 -44
  84. speclogician/presentation/models/data_artifact.py +0 -33
  85. speclogician/presentation/models/domain.py +0 -50
  86. speclogician/presentation/models/instances_list.py +0 -23
  87. speclogician/presentation/models/predicate.py +0 -60
  88. speclogician/presentation/models/recommendations.py +0 -34
  89. speclogician/presentation/models/scenario.py +0 -31
  90. speclogician/presentation/models/scenario_complement.py +0 -40
  91. speclogician/presentation/models/smart_find.py +0 -34
  92. speclogician/presentation/models/spec.py +0 -32
  93. speclogician/presentation/models/state_diff.py +0 -34
  94. speclogician/presentation/models/state_instance.py +0 -31
  95. speclogician/presentation/models/state_instance_summary.py +0 -102
  96. speclogician/presentation/models/trace.py +0 -42
  97. speclogician/presentation/preview/__init__.py +0 -13
  98. speclogician/presentation/preview/cli.py +0 -50
  99. speclogician/presentation/preview/fixtures/__init__.py +0 -205
  100. speclogician/presentation/preview/fixtures/artifact_container.py +0 -150
  101. speclogician/presentation/preview/fixtures/data_artifact.py +0 -144
  102. speclogician/presentation/preview/fixtures/domain_model.py +0 -162
  103. speclogician/presentation/preview/fixtures/instances_list.py +0 -162
  104. speclogician/presentation/preview/fixtures/predicate.py +0 -184
  105. speclogician/presentation/preview/fixtures/scenario.py +0 -84
  106. speclogician/presentation/preview/fixtures/scenario_complement.py +0 -81
  107. speclogician/presentation/preview/fixtures/smart_find.py +0 -140
  108. speclogician/presentation/preview/fixtures/spec.py +0 -95
  109. speclogician/presentation/preview/fixtures/state_diff.py +0 -158
  110. speclogician/presentation/preview/fixtures/state_instance.py +0 -128
  111. speclogician/presentation/preview/fixtures/state_instance_summary.py +0 -80
  112. speclogician/presentation/preview/fixtures/trace.py +0 -206
  113. speclogician/presentation/preview/registry.py +0 -42
  114. speclogician/presentation/renderers/__init__.py +0 -24
  115. speclogician/presentation/renderers/container.py +0 -136
  116. speclogician/presentation/renderers/data_artifact.py +0 -144
  117. speclogician/presentation/renderers/domain.py +0 -123
  118. speclogician/presentation/renderers/instances_list.py +0 -120
  119. speclogician/presentation/renderers/predicate.py +0 -180
  120. speclogician/presentation/renderers/recommendations.py +0 -90
  121. speclogician/presentation/renderers/scenario.py +0 -94
  122. speclogician/presentation/renderers/scenario_complement.py +0 -59
  123. speclogician/presentation/renderers/smart_find.py +0 -307
  124. speclogician/presentation/renderers/spec.py +0 -105
  125. speclogician/presentation/renderers/state_diff.py +0 -102
  126. speclogician/presentation/renderers/state_instance.py +0 -82
  127. speclogician/presentation/renderers/state_instance_summary.py +0 -143
  128. speclogician/presentation/renderers/trace.py +0 -122
  129. speclogician/shell/app.py +0 -170
  130. speclogician/shell/shell_ch.py +0 -263
  131. speclogician/shell/shell_view.py +0 -153
  132. speclogician/state/change_result.py +0 -32
  133. speclogician/state/diff.py +0 -191
  134. speclogician/state/inst.py +0 -574
  135. speclogician/state/recommendation.py +0 -13
  136. speclogician/state/recommender.py +0 -577
  137. speclogician/state/state_stats.py +0 -133
  138. speclogician/tui/__init__.py +0 -0
  139. speclogician/tui/app.py +0 -257
  140. speclogician/tui/app.tcss +0 -160
  141. speclogician/tui/demo.py +0 -45
  142. speclogician/tui/images/speclogician-full.png +0 -0
  143. speclogician/tui/images/speclogician-minimal.png +0 -0
  144. speclogician/tui/main_screen.py +0 -454
  145. speclogician/tui/splash_screen.py +0 -51
  146. speclogician/tui/stats_screen.py +0 -125
  147. speclogician/utils/testing.py +0 -151
  148. speclogician-0.0.0b1.dist-info/METADATA +0 -116
  149. speclogician-0.0.0b1.dist-info/RECORD +0 -139
  150. /speclogician/{presentation → agent}/__init__.py +0 -0
  151. /speclogician/{presentation/builders → cmd}/__init__.py +0 -0
  152. /speclogician/{presentation/models → llms}/__init__.py +0 -0
  153. {speclogician-0.0.0b1.dist-info → speclogician-0.0.0.dev1.dist-info}/WHEEL +0 -0
@@ -1,306 +0,0 @@
1
- #
2
- # Imandra Inc.
3
- #
4
- # speclogician/modeling/spec.py
5
- #
6
-
7
- from typing import Optional
8
- from pydantic import BaseModel, Field
9
- from collections import defaultdict
10
-
11
- from .domain import DomainModel
12
- from .complement import ScenarioComplement
13
- from .scenario import Scenario, ScenarioDelta
14
- from .conflict import ScenarioConflict
15
-
16
- def _scenario_guard_iml(scn) -> str:
17
- """
18
- given predicates are assumed: pred(s)
19
- when predicates are assumed: pred(s)(a) or pred(s, a) style; we generate pred s a.
20
- """
21
- parts: list[str] = []
22
-
23
- for p in (scn.given or []):
24
- p = (p or "").strip()
25
- if p:
26
- parts.append(f"{p} s")
27
-
28
- for p in (scn.when or []):
29
- p = (p or "").strip()
30
- if p:
31
- parts.append(f"{p} s a")
32
-
33
- return " && ".join(parts) if parts else "true"
34
-
35
-
36
- def _scenario_then_iml(scn) -> str:
37
- """
38
- then is a list of transition function names.
39
- Each transition is assumed: trans(s)(a) -> state; we generate trans s a.
40
- Applied sequentially.
41
- """
42
- thens = [(t or "").strip() for t in (scn.then or []) if (t or "").strip()]
43
- if not thens:
44
- return "s"
45
-
46
- # Apply transitions in order:
47
- # let s1 = t1 s a in let s2 = t2 s1 a in s2
48
- lines: list[str] = []
49
- cur = "s"
50
- for i, tname in enumerate(thens, start=1):
51
- nxt = f"s{i}"
52
- lines.append(f"let {nxt} = {tname} {cur} a in")
53
- cur = nxt
54
- lines.append(cur)
55
- return "\n ".join(lines)
56
-
57
-
58
- class Spec(BaseModel):
59
- """ Spec is comprised of the Domain Model and a list of Scenarios """
60
-
61
- # Domain model object also has all the relevant stats on the model
62
- domain_model : DomainModel = Field(default_factory=DomainModel)
63
-
64
- # The list of scenarios
65
- scenarios : list[Scenario] = Field(default_factory=list[Scenario])
66
-
67
- # Are there conflicts between?
68
- scenario_conflicts : list[ScenarioConflict] = Field(default_factory=list[ScenarioConflict])
69
-
70
- # Scenario complement
71
- scenario_comp : ScenarioComplement | None = None
72
-
73
- # Scenario stats
74
- num_sc_total : int = 0 # Total number of scenarios
75
- num_sc_missing : int = 0 # Missing predicates/transitions
76
- num_sc_matched : int = 0 # Total number of scenarios matched vs artifacts
77
- num_sc_inconsistent : int = 0 # Total number of scenarios inconsistent
78
-
79
- # Conflicts (spec-level)
80
- num_sc_conflicted: int = 0 # total conflicts (all kinds)
81
- num_sc_overlap: int = 0 # overlap conflicts
82
- num_sc_consumed: int = 0 # consumed conflicts
83
-
84
- def conflicts_index(self) -> dict[str, list[ScenarioConflict]]:
85
- idx: dict[str, list[ScenarioConflict]] = defaultdict(list)
86
- for c in self.scenario_conflicts:
87
- idx[c.scenario_name1].append(c)
88
- idx[c.scenario_name2].append(c)
89
- return dict(idx)
90
-
91
- def conflicts_for(self, scenario_name: str) -> list[ScenarioConflict]:
92
- return [
93
- c for c in self.scenario_conflicts
94
- if c.scenario_name1 == scenario_name or c.scenario_name2 == scenario_name
95
- ]
96
-
97
- def scenario_exists (self, name:str) -> bool:
98
- """
99
- Return True/False if scenario already exists
100
- """
101
- return any(s.name == name for s in self.scenarios)
102
-
103
- def find_scenario(self, name: str) -> Optional[Scenario]:
104
- """
105
- Return the Scenario with the given name, or None if not found.
106
- """
107
- for s in self.scenarios:
108
- if s.name == name:
109
- return s
110
- return None
111
-
112
- def _apply_delta_strict(
113
- self,
114
- current: list[str],
115
- *,
116
- delta: ScenarioDelta,
117
- allowed_add: set[str],
118
- section_label: str,
119
- ) -> list[str]:
120
- cur = set(current)
121
-
122
- # --- validate removals: must already be present ---
123
- missing_removals = set(delta.remove) - cur
124
- if missing_removals:
125
- raise ValueError(
126
- f"{section_label}: cannot remove names that are not present: {sorted(missing_removals)}"
127
- )
128
-
129
- # --- validate additions only ---
130
- bad_adds = set(delta.add) - allowed_add
131
- if bad_adds:
132
- raise ValueError(
133
- f"{section_label}: cannot add unknown names: {sorted(bad_adds)}"
134
- )
135
-
136
- # optional: forbid adding something already present
137
- already_present = set(delta.add) & cur
138
- if already_present:
139
- raise ValueError(
140
- f"{section_label}: names already present: {sorted(already_present)}"
141
- )
142
-
143
- # --- apply ---
144
- cur.difference_update(delta.remove)
145
- cur.update(delta.add)
146
-
147
- return sorted(cur) # deterministic
148
-
149
-
150
- def add_scenario(
151
- self,
152
- name: str,
153
- given: ScenarioDelta | None,
154
- when: ScenarioDelta | None,
155
- then: ScenarioDelta | None,
156
- ) -> None:
157
- """Add a new scenario. Deltas must be add-only."""
158
- if self.scenario_exists(name):
159
- raise ValueError(f"Scenario with this name already exists: [{name}]")
160
-
161
- allowed_given = set(self.domain_model.state_pred_names())
162
- allowed_when = set(self.domain_model.action_pred_names())
163
- allowed_then = set(self.domain_model.transition_names())
164
-
165
- def build_section(delta: ScenarioDelta | None, allowed: set[str], label: str) -> list[str]:
166
- if delta is None:
167
- return []
168
- if not delta.is_add_only():
169
- raise ValueError(f"{label}: 'remove' is not allowed when creating a scenario")
170
-
171
- bad = set(delta.add) - allowed
172
- if bad:
173
- raise ValueError(f"{label}: cannot add unknown names: {sorted(bad)}")
174
-
175
- return sorted(set(delta.add)) # set semantics, deterministic
176
-
177
- new_given = build_section(given, allowed_given, f"Scenario '{name}' given")
178
- new_when = build_section(when, allowed_when, f"Scenario '{name}' when")
179
- new_then = build_section(then, allowed_then, f"Scenario '{name}' then")
180
-
181
- self.scenarios.append(
182
- Scenario(name=name, given=new_given, when=new_when, then=new_then)
183
- )
184
-
185
- def edit_scenario(
186
- self,
187
- name: str,
188
- given: Optional[ScenarioDelta],
189
- when: Optional[ScenarioDelta],
190
- then: Optional[ScenarioDelta],
191
- ) -> None:
192
- """Edit an existing scenario with strict validation (checks only on add)."""
193
- scenario = self.find_scenario(name)
194
- if scenario is None:
195
- raise ValueError(f"Scenario '{name}' not found")
196
-
197
- allowed_given = set(self.domain_model.state_pred_names())
198
- allowed_when = set(self.domain_model.action_pred_names())
199
- allowed_then = set(self.domain_model.transition_names())
200
-
201
- if given is not None:
202
- scenario.given = self._apply_delta_strict(
203
- list(scenario.given),
204
- delta=given,
205
- allowed_add=allowed_given,
206
- section_label=f"Scenario '{name}' given",
207
- )
208
-
209
- if when is not None:
210
- scenario.when = self._apply_delta_strict(
211
- list(scenario.when),
212
- delta=when,
213
- allowed_add=allowed_when,
214
- section_label=f"Scenario '{name}' when",
215
- )
216
-
217
- if then is not None:
218
- scenario.then = self._apply_delta_strict(
219
- list(scenario.then),
220
- delta=then,
221
- allowed_add=allowed_then,
222
- section_label=f"Scenario '{name}' then",
223
- )
224
-
225
- def rem_scenario(self, name: str) -> None:
226
- """Remove a scenario by name."""
227
- for i, s in enumerate(self.scenarios):
228
- if s.name == name:
229
- del self.scenarios[i]
230
- return
231
- raise ValueError(f"Scenario '{name}' not found")
232
-
233
- def scenario_model(self):
234
- """
235
- Synthesize a model from the scenarios
236
- """
237
-
238
- scenario_logic = ""
239
- for s in self.scenarios:
240
- scenario_logic += f"{s.full_model_to_iml()}\n"
241
-
242
- model = f"""
243
- let scenarios (s : state) (a : action) =
244
- {scenario_logic} else
245
- false
246
- """
247
- return model
248
-
249
- def _scenarios_main_iml(self) -> str:
250
- """
251
- Compile scenarios into a single dispatcher function `main`.
252
- Scenarios are tried in list order (priority order).
253
- """
254
- if not self.scenarios:
255
- return "let main (s: state) (_a: action) : state = s"
256
-
257
- lines: list[str] = []
258
- lines.append("let main (s: state) (a: action) : state =")
259
-
260
- for idx, scn in enumerate(self.scenarios):
261
- guard = _scenario_guard_iml(scn)
262
- body = _scenario_then_iml(scn)
263
-
264
- kw = "if" if idx == 0 else "else if"
265
- lines.append(f" {kw} {guard} then")
266
- # indent body nicely
267
- body_lines = body.splitlines() or ["s"]
268
- lines.append(" " + "\n ".join(body_lines))
269
-
270
- lines.append(" else s")
271
- return "\n".join(lines)
272
-
273
- def full_model(self) -> str:
274
- """
275
- Return the full model (base + predicates + transitions + scenarios)
276
- as a single executable IML program.
277
- """
278
- dm = self.domain_model
279
-
280
- parts: list[str] = []
281
-
282
- # 1. Base domain
283
- if dm.base:
284
- parts.append(dm.base.strip())
285
-
286
- # 2. Predicates
287
- if dm.state_preds or dm.action_preds:
288
- parts.append("\n(* Predicates *)\n")
289
- for p in dm.state_preds:
290
- parts.append(p.to_iml().strip())
291
- for p in dm.action_preds:
292
- parts.append(p.to_iml().strip())
293
-
294
- # 3. Transitions
295
- if dm.transitions:
296
- parts.append("\n(* Transitions *)\n")
297
- for t in dm.transitions:
298
- parts.append(t.to_iml().strip())
299
-
300
- # 4. Scenarios
301
- if self.scenarios:
302
- parts.append("\n(* Scenario dispatcher *)\n")
303
- parts.append(self._scenarios_main_iml().strip())
304
-
305
- # Join with clean spacing
306
- return "\n\n".join(p for p in parts if p.strip())
@@ -1,39 +0,0 @@
1
- #
2
- # Imandra Inc.
3
- #
4
- # speclogician/modeling/spec_stats.py
5
- #
6
-
7
-
8
- from __future__ import annotations
9
-
10
- from speclogician.data.mapping import ArtifactMap
11
- from speclogician.modeling.conflict import ScenarioConsumed, ScenarioOverlap
12
- from speclogician.modeling.scenario import Inconsistent, Missing
13
- from speclogician.modeling.spec import Spec
14
-
15
-
16
- def refresh_spec_stats(spec: Spec, *, art_map: ArtifactMap | None) -> None:
17
- # ---- scenarios ----
18
- spec.num_sc_total = len(spec.scenarios)
19
-
20
- spec.num_sc_missing = sum(
21
- 1 for sc in spec.scenarios if isinstance(getattr(sc, "component_status", None), Missing)
22
- )
23
- spec.num_sc_inconsistent = sum(
24
- 1 for sc in spec.scenarios if isinstance(getattr(sc, "component_status", None), Inconsistent)
25
- )
26
-
27
- # “matched” should be keyed by scenario.comp_id (NOT name)
28
- if art_map is None:
29
- spec.num_sc_matched = 0
30
- else:
31
- comp_to_art = getattr(art_map, "comp_to_art_map", {}) or {}
32
- spec.num_sc_matched = sum(
33
- 1 for sc in spec.scenarios if len(comp_to_art.get(sc.comp_id, [])) > 0
34
- )
35
-
36
- # ---- conflicts (spec-level) ----
37
- spec.num_sc_conflicted = len(spec.scenario_conflicts or [])
38
- spec.num_sc_overlap = sum(isinstance(c, ScenarioOverlap) for c in (spec.scenario_conflicts or []))
39
- spec.num_sc_consumed = sum(isinstance(c, ScenarioConsumed) for c in (spec.scenario_conflicts or []))
@@ -1,244 +0,0 @@
1
- #
2
- # Imandra Inc.
3
- #
4
- # speclogician/presentation/api.py
5
- #
6
-
7
- from __future__ import annotations
8
-
9
- # --- Controls how we print things out (and also contains some data)
10
- from speclogician.presentation.ctx import RenderCtx
11
-
12
- # --- Underlying models
13
- from speclogician.modeling.predicates import ActionPredicate, StatePredicate, Transition
14
- from speclogician.modeling.domain import DomainModel
15
- from speclogician.modeling.spec import Spec
16
- from speclogician.modeling.complement import ScenarioComplement
17
- from speclogician.data.traces import TestTrace, LogTrace
18
- from speclogician.data.refs import DocRef, SrcCodeRef
19
- from speclogician.data.container import ArtifactContainer, SmartFindResults
20
- from speclogician.state.inst import StateInstance
21
- from speclogician.state.diff import StateDiff
22
- from speclogician.modeling.scenario import Scenario
23
- from speclogician.state.recommender import Recommendation
24
-
25
- # --- Builders
26
- from speclogician.presentation.builders.predicate import (
27
- build_predicate_pm,
28
- build_transition_pm,
29
- )
30
- from speclogician.presentation.builders.domain import build_domain_model_pm
31
- from speclogician.presentation.builders.trace import build_test_trace_pm, build_log_trace_pm
32
- from speclogician.presentation.builders.spec import build_spec_pm
33
- from speclogician.presentation.builders.scenario import build_scenario_pm
34
- from speclogician.presentation.builders.data_artifact import build_doc_ref_pm, build_src_code_ref_pm
35
- from speclogician.presentation.builders.container import build_artifact_container_pm
36
- from speclogician.presentation.builders.smart_find import build_smart_find_pm
37
- from speclogician.presentation.builders.state_instance import build_state_instance_pm
38
- from speclogician.presentation.builders.state_diff import build_state_diff_pm
39
- from speclogician.presentation.builders.instances_list import build_instances_list_pm
40
- from speclogician.presentation.builders.recommendations import build_recommendations_pm
41
- from speclogician.presentation.builders.scenario_complement import build_scenario_complement_pm
42
-
43
-
44
- # --- Renderers
45
- from speclogician.presentation.renderers.predicate import (
46
- render_predicate,
47
- render_transition,
48
- )
49
- from speclogician.presentation.renderers.trace import render_test_trace, render_log_trace
50
- from speclogician.presentation.renderers.domain import render_domain_model
51
- from speclogician.presentation.renderers.spec import render_spec
52
- from speclogician.presentation.renderers.scenario import render_scenario
53
- from speclogician.presentation.renderers.data_artifact import render_doc_ref, render_src_code_ref
54
- from speclogician.presentation.renderers.container import render_artifact_container
55
- from speclogician.presentation.renderers.smart_find import render_smart_find
56
- from speclogician.presentation.renderers.state_instance import render_state_instance
57
- from speclogician.presentation.renderers.state_diff import render_state_diff
58
- from speclogician.presentation.renderers.instances_list import render_instances_list
59
- from speclogician.presentation.renderers.recommendations import render_recommendations
60
- from speclogician.presentation.renderers.scenario_complement import render_scenario_complement
61
-
62
-
63
- def present_predicate(
64
- p: StatePredicate | ActionPredicate,
65
- *,
66
- ctx: RenderCtx,
67
- json_only: bool,
68
- ):
69
- pm = build_predicate_pm(p, ctx)
70
- if json_only:
71
- return pm.model_dump()
72
- return render_predicate(pm, ctx=ctx)
73
-
74
-
75
- def present_transition(
76
- t: Transition,
77
- *,
78
- ctx: RenderCtx,
79
- json_only: bool,
80
- ):
81
- pm = build_transition_pm(t, ctx)
82
- if json_only:
83
- return pm.model_dump()
84
- return render_transition(pm, ctx=ctx)
85
-
86
-
87
- def present_domain_model(
88
- dm: DomainModel,
89
- *,
90
- ctx: RenderCtx,
91
- json_only: bool,
92
- ):
93
- pm = build_domain_model_pm(dm, ctx)
94
- if json_only:
95
- return pm.model_dump()
96
- return render_domain_model(pm, ctx=ctx)
97
-
98
-
99
- def present_spec(
100
- spec: Spec,
101
- *,
102
- ctx: RenderCtx,
103
- json_only: bool,
104
- ):
105
- pm = build_spec_pm(spec, ctx)
106
- if json_only:
107
- return pm.model_dump()
108
- return render_spec(pm, ctx=ctx)
109
-
110
-
111
- def present_scenario_complement(
112
- comp: ScenarioComplement,
113
- *,
114
- ctx: RenderCtx,
115
- json_only: bool,
116
- ):
117
- pm = build_scenario_complement_pm(comp, ctx)
118
- if json_only:
119
- return pm.model_dump()
120
- return render_scenario_complement(pm, ctx=ctx)
121
-
122
-
123
- def present_trace(
124
- tr: TestTrace | LogTrace,
125
- *,
126
- ctx: RenderCtx,
127
- json_only: bool,
128
- ):
129
- if isinstance(tr, TestTrace):
130
- pm = build_test_trace_pm(tr, ctx)
131
- if json_only:
132
- return pm.model_dump()
133
- return render_test_trace(pm, ctx=ctx)
134
-
135
- if isinstance(tr, LogTrace):
136
- pm = build_log_trace_pm(tr, ctx)
137
- if json_only:
138
- return pm.model_dump()
139
- return render_log_trace(pm, ctx=ctx)
140
-
141
- raise TypeError(f"Unsupported trace type: {type(tr).__name__}")
142
-
143
-
144
- def present_data_artifact(
145
- a: DocRef | SrcCodeRef,
146
- *,
147
- ctx: RenderCtx,
148
- json_only: bool,
149
- ):
150
- if isinstance(a, DocRef):
151
- pm = build_doc_ref_pm(a, ctx)
152
- if json_only:
153
- return pm.model_dump()
154
- return render_doc_ref(pm, ctx=ctx)
155
-
156
- if isinstance(a, SrcCodeRef):
157
- pm = build_src_code_ref_pm(a, ctx)
158
- if json_only:
159
- return pm.model_dump()
160
- return render_src_code_ref(pm, ctx=ctx)
161
-
162
- raise TypeError(f"Unsupported data artifact type: {type(a).__name__}")
163
-
164
-
165
- def present_artifact_container(
166
- cont: ArtifactContainer,
167
- *,
168
- ctx: RenderCtx,
169
- json_only: bool,
170
- ):
171
- pm = build_artifact_container_pm(cont, ctx)
172
- if json_only:
173
- return pm.model_dump()
174
- return render_artifact_container(pm, ctx=ctx)
175
-
176
-
177
- def present_smart_find(
178
- res: SmartFindResults,
179
- *,
180
- ctx: RenderCtx,
181
- json_only: bool,
182
- ):
183
- pm = build_smart_find_pm(res, ctx)
184
- if json_only:
185
- return pm.model_dump()
186
- return render_smart_find(pm, ctx=ctx)
187
-
188
-
189
- def present_state_diff(
190
- sd: StateDiff,
191
- *,
192
- ctx: RenderCtx,
193
- json_only: bool,
194
- ):
195
- pm = build_state_diff_pm(sd, ctx)
196
- if json_only:
197
- return pm.model_dump()
198
- return render_state_diff(pm, ctx=ctx)
199
-
200
-
201
- def present_state_instance(
202
- si: StateInstance,
203
- *,
204
- ctx: RenderCtx,
205
- json_only: bool,
206
- ):
207
- pm = build_state_instance_pm(si, ctx)
208
- if json_only:
209
- return pm.model_dump()
210
- return render_state_instance(pm, ctx=ctx)
211
-
212
-
213
- def present_scenario(
214
- sc: Scenario,
215
- *,
216
- ctx: RenderCtx,
217
- json_only: bool,
218
- ):
219
- pm = build_scenario_pm(sc, ctx)
220
- if json_only:
221
- return pm.model_dump()
222
- return render_scenario(pm, ctx=ctx)
223
-
224
-
225
- def present_instances_list(
226
- states: list[StateInstance],
227
- *,
228
- ctx: RenderCtx,
229
- json_only: bool,
230
- ):
231
- pm = build_instances_list_pm(states, ctx)
232
- if json_only:
233
- return pm.model_dump()
234
- return render_instances_list(pm, ctx=ctx)
235
-
236
-
237
- def present_recommendations(
238
- recs: list[Recommendation],
239
- *,
240
- ctx: RenderCtx,
241
- json_only: bool,
242
- ):
243
- pm = build_recommendations_pm(recs, ctx)
244
- return pm.model_dump() if json_only else render_recommendations(pm, ctx=ctx)
@@ -1,44 +0,0 @@
1
- #
2
- # Imandra Inc.
3
- #
4
- # speclogician/presentation/builders/_links.py
5
- #
6
-
7
- from __future__ import annotations
8
-
9
- from speclogician.presentation.ctx import RenderCtx
10
- from speclogician.presentation.models.predicate import LinkedArtifactsPM
11
- from speclogician.data.traces import TestTrace, LogTrace
12
- from speclogician.data.refs import DocRef, SrcCodeRef
13
-
14
-
15
- def build_links_pm(comp_id: str, ctx: RenderCtx) -> LinkedArtifactsPM:
16
- links = LinkedArtifactsPM()
17
-
18
- if ctx.art_map is None:
19
- return links
20
-
21
- art_ids = list(ctx.art_map.get_arts_for_component(comp_id))
22
- links.total = len(art_ids)
23
- links.art_ids = art_ids if ctx.show_art_ids else []
24
-
25
- if ctx.art_cont is None:
26
- links.unresolved_ids = len(art_ids)
27
- return links
28
-
29
- unresolved = 0
30
- for aid in art_ids:
31
- a = ctx.art_cont.get_by_art_id(aid)
32
- if a is None:
33
- unresolved += 1
34
- elif isinstance(a, TestTrace):
35
- links.test_traces += 1
36
- elif isinstance(a, LogTrace):
37
- links.log_traces += 1
38
- elif isinstance(a, DocRef):
39
- links.doc_refs += 1
40
- elif isinstance(a, SrcCodeRef):
41
- links.src_code_refs += 1
42
-
43
- links.unresolved_ids = unresolved
44
- return links
@@ -1,53 +0,0 @@
1
- #
2
- # Imandra Inc.
3
- #
4
- # speclogician/presentation/builders/container.py
5
- #
6
-
7
- from __future__ import annotations
8
-
9
- from speclogician.data.container import ArtifactContainer
10
- from speclogician.presentation.ctx import RenderCtx
11
-
12
- from speclogician.presentation.models.container import (
13
- ArtifactContainerPM,
14
- ArtifactContainerCountsPM,
15
- ArtifactContainerItemsPM,
16
- )
17
-
18
- from speclogician.presentation.builders.trace import build_test_trace_pm, build_log_trace_pm
19
- from speclogician.presentation.builders.data_artifact import build_doc_ref_pm, build_src_code_ref_pm
20
-
21
-
22
- def build_artifact_container_pm(cont: ArtifactContainer, ctx: RenderCtx) -> ArtifactContainerPM:
23
- counts = ArtifactContainerCountsPM(
24
- num_test_traces_total=cont.num_test_traces_total,
25
- num_test_traces_matched=cont.num_test_traces_matched,
26
- num_test_traces_logic_good=cont.num_test_traces_logic_good,
27
- num_log_traces_total=cont.num_log_traces_total,
28
- num_log_traces_matched=cont.num_log_traces_matched,
29
- num_log_traces_logic_good=cont.num_log_traces_logic_good,
30
- num_src_code_arts_total=cont.num_src_code_arts_total,
31
- num_src_code_arts_matched=cont.num_src_code_arts_matched,
32
- num_doc_arts_total=cont.num_doc_arts_total,
33
- num_doc_arts_matched=cont.num_doc_arts_matched,
34
- )
35
-
36
- items = ArtifactContainerItemsPM()
37
-
38
- if not ctx.show_stats_only:
39
- if ctx.show_traces:
40
- items.test_traces = [build_test_trace_pm(t, ctx) for t in cont.test_traces]
41
- items.log_traces = [build_log_trace_pm(t, ctx) for t in cont.log_traces]
42
- else:
43
- items.test_traces = []
44
- items.log_traces = []
45
-
46
- if ctx.show_artifacts:
47
- items.doc_refs = [build_doc_ref_pm(d, ctx) for d in cont.doc_ref]
48
- items.src_code_refs = [build_src_code_ref_pm(s, ctx) for s in cont.src_code]
49
- else:
50
- items.doc_refs = []
51
- items.src_code_refs = []
52
-
53
- return ArtifactContainerPM(counts=counts, items=items)