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.
- speclogician/agent/funcs.py +29 -0
- speclogician/cmd/agent_cmd.py +89 -0
- speclogician/cmd/data_cmd.py +24 -0
- speclogician/cmd/model_cmd.py +42 -0
- speclogician/cmd/overlay_cmd.py +30 -0
- speclogician/cmd/scenario_cmd.py +61 -0
- speclogician/cmd/state_cmd.py +52 -0
- speclogician/data/artifact.py +8 -50
- speclogician/data/container.py +18 -384
- speclogician/data/mapping.py +18 -17
- speclogician/data/refs.py +12 -11
- speclogician/data/reports.py +11 -0
- speclogician/data/traces.py +15 -6
- speclogician/llms/llmtools.py +102 -0
- speclogician/llms/overlay.py +264 -0
- speclogician/main.py +36 -102
- speclogician/modeling/__init__.py +0 -31
- speclogician/modeling/component.py +4 -60
- speclogician/modeling/conflict.py +5 -19
- speclogician/modeling/domain.py +93 -280
- speclogician/modeling/model.py +206 -0
- speclogician/modeling/predicates.py +20 -22
- speclogician/modeling/report.py +33 -0
- speclogician/modeling/scenario.py +119 -87
- speclogician/sl_cmd.py +76 -0
- speclogician/state/change.py +98 -378
- speclogician/state/state.py +183 -399
- speclogician/tui/box.tcss +10 -0
- speclogician/tui/tui.py +131 -0
- speclogician/utils/__init__.py +1 -70
- speclogician/utils/imx.py +195 -0
- speclogician/utils/load.py +25 -147
- speclogician/utils/prompt.md +1 -325
- speclogician-0.0.0.dev1.dist-info/METADATA +21 -0
- speclogician-0.0.0.dev1.dist-info/RECORD +43 -0
- speclogician/commands/__init__.py +0 -15
- speclogician/commands/cmd_ch.py +0 -616
- speclogician/commands/cmd_find.py +0 -256
- speclogician/commands/cmd_view.py +0 -202
- speclogician/commands/runner.py +0 -149
- speclogician/commands/utils.py +0 -101
- speclogician/demos/.DS_Store +0 -0
- speclogician/demos/cmd_demo.py +0 -278
- speclogician/demos/loader.py +0 -135
- speclogician/demos/model.py +0 -27
- speclogician/demos/runner.py +0 -51
- speclogician/logic/__init__.py +0 -11
- speclogician/logic/api/__init__.py +0 -29
- speclogician/logic/api/client.py +0 -606
- speclogician/logic/api/decomp.py +0 -67
- speclogician/logic/api/scenario.py +0 -102
- speclogician/logic/api/traces.py +0 -59
- speclogician/logic/lib/__init__.py +0 -19
- speclogician/logic/lib/complement.py +0 -107
- speclogician/logic/lib/domain_model.py +0 -59
- speclogician/logic/lib/predicates.py +0 -151
- speclogician/logic/lib/scenarios.py +0 -369
- speclogician/logic/lib/traces.py +0 -114
- speclogician/logic/lib/transitions.py +0 -104
- speclogician/logic/main.py +0 -246
- speclogician/logic/strings.py +0 -194
- speclogician/logic/utils.py +0 -135
- speclogician/modeling/complement.py +0 -104
- speclogician/modeling/spec.py +0 -306
- speclogician/modeling/spec_stats.py +0 -39
- speclogician/presentation/api.py +0 -244
- speclogician/presentation/builders/_links.py +0 -44
- speclogician/presentation/builders/container.py +0 -53
- speclogician/presentation/builders/data_artifact.py +0 -42
- speclogician/presentation/builders/domain.py +0 -54
- speclogician/presentation/builders/instances_list.py +0 -38
- speclogician/presentation/builders/predicate.py +0 -51
- speclogician/presentation/builders/recommendations.py +0 -41
- speclogician/presentation/builders/scenario.py +0 -41
- speclogician/presentation/builders/scenario_complement.py +0 -82
- speclogician/presentation/builders/smart_find.py +0 -39
- speclogician/presentation/builders/spec.py +0 -39
- speclogician/presentation/builders/state_diff.py +0 -150
- speclogician/presentation/builders/state_instance.py +0 -42
- speclogician/presentation/builders/state_instance_summary.py +0 -84
- speclogician/presentation/builders/trace.py +0 -58
- speclogician/presentation/ctx.py +0 -38
- speclogician/presentation/models/container.py +0 -44
- speclogician/presentation/models/data_artifact.py +0 -33
- speclogician/presentation/models/domain.py +0 -50
- speclogician/presentation/models/instances_list.py +0 -23
- speclogician/presentation/models/predicate.py +0 -60
- speclogician/presentation/models/recommendations.py +0 -34
- speclogician/presentation/models/scenario.py +0 -31
- speclogician/presentation/models/scenario_complement.py +0 -40
- speclogician/presentation/models/smart_find.py +0 -34
- speclogician/presentation/models/spec.py +0 -32
- speclogician/presentation/models/state_diff.py +0 -34
- speclogician/presentation/models/state_instance.py +0 -31
- speclogician/presentation/models/state_instance_summary.py +0 -102
- speclogician/presentation/models/trace.py +0 -42
- speclogician/presentation/preview/__init__.py +0 -13
- speclogician/presentation/preview/cli.py +0 -50
- speclogician/presentation/preview/fixtures/__init__.py +0 -205
- speclogician/presentation/preview/fixtures/artifact_container.py +0 -150
- speclogician/presentation/preview/fixtures/data_artifact.py +0 -144
- speclogician/presentation/preview/fixtures/domain_model.py +0 -162
- speclogician/presentation/preview/fixtures/instances_list.py +0 -162
- speclogician/presentation/preview/fixtures/predicate.py +0 -184
- speclogician/presentation/preview/fixtures/scenario.py +0 -84
- speclogician/presentation/preview/fixtures/scenario_complement.py +0 -81
- speclogician/presentation/preview/fixtures/smart_find.py +0 -140
- speclogician/presentation/preview/fixtures/spec.py +0 -95
- speclogician/presentation/preview/fixtures/state_diff.py +0 -158
- speclogician/presentation/preview/fixtures/state_instance.py +0 -128
- speclogician/presentation/preview/fixtures/state_instance_summary.py +0 -80
- speclogician/presentation/preview/fixtures/trace.py +0 -206
- speclogician/presentation/preview/registry.py +0 -42
- speclogician/presentation/renderers/__init__.py +0 -24
- speclogician/presentation/renderers/container.py +0 -136
- speclogician/presentation/renderers/data_artifact.py +0 -144
- speclogician/presentation/renderers/domain.py +0 -123
- speclogician/presentation/renderers/instances_list.py +0 -120
- speclogician/presentation/renderers/predicate.py +0 -180
- speclogician/presentation/renderers/recommendations.py +0 -90
- speclogician/presentation/renderers/scenario.py +0 -94
- speclogician/presentation/renderers/scenario_complement.py +0 -59
- speclogician/presentation/renderers/smart_find.py +0 -307
- speclogician/presentation/renderers/spec.py +0 -105
- speclogician/presentation/renderers/state_diff.py +0 -102
- speclogician/presentation/renderers/state_instance.py +0 -82
- speclogician/presentation/renderers/state_instance_summary.py +0 -143
- speclogician/presentation/renderers/trace.py +0 -122
- speclogician/shell/app.py +0 -170
- speclogician/shell/shell_ch.py +0 -263
- speclogician/shell/shell_view.py +0 -153
- speclogician/state/change_result.py +0 -32
- speclogician/state/diff.py +0 -191
- speclogician/state/inst.py +0 -574
- speclogician/state/recommendation.py +0 -13
- speclogician/state/recommender.py +0 -577
- speclogician/state/state_stats.py +0 -133
- speclogician/tui/__init__.py +0 -0
- speclogician/tui/app.py +0 -257
- speclogician/tui/app.tcss +0 -160
- speclogician/tui/demo.py +0 -45
- speclogician/tui/images/speclogician-full.png +0 -0
- speclogician/tui/images/speclogician-minimal.png +0 -0
- speclogician/tui/main_screen.py +0 -454
- speclogician/tui/splash_screen.py +0 -51
- speclogician/tui/stats_screen.py +0 -125
- speclogician/utils/testing.py +0 -151
- speclogician-0.0.0b1.dist-info/METADATA +0 -116
- speclogician-0.0.0b1.dist-info/RECORD +0 -139
- /speclogician/{presentation → agent}/__init__.py +0 -0
- /speclogician/{presentation/builders → cmd}/__init__.py +0 -0
- /speclogician/{presentation/models → llms}/__init__.py +0 -0
- {speclogician-0.0.0b1.dist-info → speclogician-0.0.0.dev1.dist-info}/WHEEL +0 -0
speclogician/state/change.py
CHANGED
|
@@ -1,428 +1,148 @@
|
|
|
1
1
|
#
|
|
2
2
|
# Imandra Inc.
|
|
3
3
|
#
|
|
4
|
-
#
|
|
4
|
+
# change.py
|
|
5
5
|
#
|
|
6
6
|
|
|
7
|
-
from
|
|
7
|
+
from pydantic import BaseModel
|
|
8
|
+
# from typing import Optional
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
from pydantic import BaseModel, Field, computed_field, model_validator
|
|
13
|
-
from typing import Literal, Optional
|
|
14
|
-
|
|
15
|
-
from ..modeling.domain import PredicateType
|
|
16
|
-
from ..modeling.scenario import ScenarioDelta
|
|
17
|
-
|
|
18
|
-
ProcessChangeStage = Literal["apply_change", "analyze_change", "calc_diff", "ok"]
|
|
19
|
-
|
|
20
|
-
class StateChange(BaseModel):
|
|
21
|
-
""" StateChange """
|
|
22
|
-
|
|
23
|
-
meta : str | None = None
|
|
24
|
-
|
|
25
|
-
@computed_field
|
|
26
|
-
@property
|
|
27
|
-
def kind(self) -> str:
|
|
28
|
-
return self.__class__.__name__
|
|
29
|
-
|
|
30
|
-
def short_str(self) -> str:
|
|
31
|
-
return f"[bold deep_blue_sky]{self.kind}[/bold deep_blue_sky]"
|
|
10
|
+
class ModelChange(BaseModel):
|
|
11
|
+
"""
|
|
12
|
+
"""
|
|
32
13
|
|
|
33
|
-
def
|
|
34
|
-
|
|
35
|
-
for k, v in self.model_dump(exclude_none=True, exclude={"kind"}).items():
|
|
36
|
-
rows.append(Text(f"{k} = {v!r}"))
|
|
37
|
-
return Panel(
|
|
38
|
-
Group(*rows),
|
|
39
|
-
title=f"[italic]{self.__class__.__name__}[/]",
|
|
40
|
-
title_align="left",
|
|
41
|
-
)
|
|
14
|
+
def short_str(self):
|
|
15
|
+
return ""
|
|
42
16
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
# ----------------------------
|
|
17
|
+
def __str__ (self):
|
|
18
|
+
return ""
|
|
46
19
|
|
|
47
|
-
class DomainModelBaseEdit(
|
|
48
|
-
"""
|
|
49
|
-
|
|
20
|
+
class DomainModelBaseEdit(BaseModel):
|
|
21
|
+
"""
|
|
22
|
+
"""
|
|
23
|
+
new_base_src : str
|
|
50
24
|
|
|
51
|
-
def short_str(self)
|
|
52
|
-
|
|
25
|
+
def short_str(self):
|
|
26
|
+
""" """
|
|
27
|
+
return ''
|
|
53
28
|
|
|
54
|
-
def __str__ (self)
|
|
29
|
+
def __str__ (self):
|
|
55
30
|
return ""
|
|
56
31
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
pred_type : PredicateType = Field(..., description="Predicate add")
|
|
64
|
-
pred_name : str = Field(..., description="predicate name (no spaces). no signature.")
|
|
65
|
-
pred_src : str = Field(..., description="predicate source code")
|
|
32
|
+
class PredicateAdd(BaseModel):
|
|
33
|
+
"""
|
|
34
|
+
"""
|
|
35
|
+
pred_type : str
|
|
36
|
+
pred_name : str
|
|
37
|
+
pred_src : str
|
|
66
38
|
|
|
67
39
|
def short_str(self):
|
|
68
40
|
""" """
|
|
69
|
-
return
|
|
41
|
+
return f''
|
|
70
42
|
|
|
71
43
|
def __str__(self):
|
|
72
44
|
return ""
|
|
73
45
|
|
|
74
|
-
class PredicateEdit(
|
|
75
|
-
"""
|
|
76
|
-
|
|
77
|
-
|
|
46
|
+
class PredicateEdit(BaseModel):
|
|
47
|
+
"""
|
|
48
|
+
"""
|
|
49
|
+
pred_name : str
|
|
50
|
+
pred_src : str
|
|
78
51
|
|
|
79
52
|
def short_str(self):
|
|
80
|
-
return
|
|
53
|
+
return f'PredicateEdit: name={self.pred_name}'
|
|
81
54
|
|
|
82
55
|
def __str__(self):
|
|
83
56
|
return f'PredicateEdit: {self.pred_name}'
|
|
84
57
|
|
|
85
|
-
class PredicateRemove(
|
|
86
|
-
"""
|
|
87
|
-
|
|
58
|
+
class PredicateRemove(BaseModel):
|
|
59
|
+
"""
|
|
60
|
+
"""
|
|
61
|
+
pred_name : str
|
|
88
62
|
|
|
89
|
-
def short_str(self)
|
|
63
|
+
def short_str(self):
|
|
90
64
|
return f'PredicateRemove: name = {self.pred_name}'
|
|
91
65
|
|
|
92
|
-
def __str__(self)
|
|
93
|
-
return
|
|
94
|
-
|
|
95
|
-
# ----------------------------
|
|
96
|
-
# Transitions
|
|
97
|
-
# ----------------------------
|
|
66
|
+
def __str__(self):
|
|
67
|
+
return "PredicateRemove"
|
|
98
68
|
|
|
99
|
-
class TransitionAdd(
|
|
100
|
-
"""
|
|
101
|
-
|
|
102
|
-
|
|
69
|
+
class TransitionAdd(BaseModel):
|
|
70
|
+
"""
|
|
71
|
+
"""
|
|
72
|
+
pred_name : str
|
|
73
|
+
pred_src : str
|
|
103
74
|
|
|
104
|
-
def short_str(self)
|
|
105
|
-
return ''
|
|
75
|
+
def short_str(self):
|
|
76
|
+
return f''
|
|
106
77
|
|
|
107
|
-
def __str__(self)
|
|
108
|
-
return
|
|
78
|
+
def __str__(self):
|
|
79
|
+
return "TransitionAdd: "
|
|
109
80
|
|
|
110
|
-
class TransitionEdit(
|
|
111
|
-
"""
|
|
112
|
-
|
|
113
|
-
|
|
81
|
+
class TransitionEdit(BaseModel):
|
|
82
|
+
"""
|
|
83
|
+
"""
|
|
84
|
+
tran_name : str
|
|
85
|
+
tran_src : str
|
|
114
86
|
|
|
115
87
|
def short_str(self):
|
|
116
|
-
return f
|
|
88
|
+
return f''
|
|
117
89
|
|
|
118
90
|
def __str__(self):
|
|
119
91
|
return "TransitionEdit: "
|
|
120
92
|
|
|
121
|
-
class TransitionRemove(
|
|
122
|
-
"""
|
|
123
|
-
|
|
93
|
+
class TransitionRemove(BaseModel):
|
|
94
|
+
""" """
|
|
95
|
+
tran_name : str
|
|
124
96
|
|
|
125
97
|
def short_str(self):
|
|
126
|
-
return
|
|
98
|
+
return ''
|
|
127
99
|
|
|
128
100
|
def __str__(self):
|
|
129
101
|
return "TransitionRemove: "
|
|
130
102
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
103
|
+
class ScenarioAdd(ModelChange):
|
|
104
|
+
"""
|
|
105
|
+
Add a new scenario
|
|
106
|
+
"""
|
|
107
|
+
name : str
|
|
134
108
|
|
|
135
|
-
|
|
109
|
+
def __str__(self):
|
|
110
|
+
return ""
|
|
111
|
+
|
|
112
|
+
class ScenarioEdit(ModelChange):
|
|
136
113
|
"""
|
|
137
|
-
|
|
138
|
-
For creation, deltas must be add-only (remove must be empty).
|
|
114
|
+
Edit a scenario
|
|
139
115
|
"""
|
|
140
|
-
scenario_name: str
|
|
141
|
-
|
|
142
|
-
when: Optional[ScenarioDelta] = None
|
|
143
|
-
then: Optional[ScenarioDelta] = None
|
|
144
|
-
|
|
145
|
-
@model_validator(mode="after")
|
|
146
|
-
def _add_only(self) -> "ScenarioAdd":
|
|
147
|
-
for sec_name, delta in (("given", self.given), ("when", self.when), ("then", self.then)):
|
|
148
|
-
if delta is not None and not delta.is_add_only():
|
|
149
|
-
raise ValueError(f"ScenarioAdd.{sec_name}: 'remove' is not allowed when creating a scenario")
|
|
150
|
-
return self
|
|
151
|
-
|
|
152
|
-
def short_str(self) -> str:
|
|
153
|
-
return f"ScenarioAdd: name={self.scenario_name}"
|
|
154
|
-
|
|
155
|
-
Section = Literal["given", "when", "then"]
|
|
156
|
-
|
|
157
|
-
class ScenarioEdit(StateChange):
|
|
158
|
-
scenario_name: str
|
|
159
|
-
given: ScenarioDelta | None = None
|
|
160
|
-
when: ScenarioDelta | None = None
|
|
161
|
-
then: ScenarioDelta | None = None
|
|
162
|
-
|
|
163
|
-
@model_validator(mode="after")
|
|
164
|
-
def _must_have_some_delta(self) -> "ScenarioEdit":
|
|
165
|
-
deltas = [d for d in (self.given, self.when, self.then) if d is not None]
|
|
166
|
-
|
|
167
|
-
if not deltas:
|
|
168
|
-
raise ValueError("At least one of given/when/then must be provided.")
|
|
169
|
-
|
|
170
|
-
if all(d.is_empty() for d in deltas):
|
|
171
|
-
raise ValueError("ScenarioEdit has no effect: all provided deltas are empty.")
|
|
172
|
-
|
|
173
|
-
return self
|
|
174
|
-
|
|
175
|
-
def short_str(self) -> str:
|
|
176
|
-
parts = []
|
|
177
|
-
for sec in ("given", "when", "then"):
|
|
178
|
-
delta = getattr(self, sec)
|
|
179
|
-
if delta:
|
|
180
|
-
if delta.add:
|
|
181
|
-
parts.append(f"{sec} +{delta.add}")
|
|
182
|
-
if delta.remove:
|
|
183
|
-
parts.append(f"{sec} -{delta.remove}")
|
|
184
|
-
return f"ScenarioStepsEdit[{self.scenario_name}]: " + ", ".join(parts)
|
|
185
|
-
|
|
186
|
-
class ScenarioRemove(StateChange):
|
|
187
|
-
""" Remove an existing scenario """
|
|
188
|
-
scenario_name : str = Field(..., description="Name of the scenario to remove")
|
|
189
|
-
|
|
116
|
+
scenario_name : str
|
|
117
|
+
|
|
190
118
|
def short_str(self):
|
|
191
|
-
return f
|
|
192
|
-
|
|
193
|
-
# ----------------------------
|
|
194
|
-
# Test traces
|
|
195
|
-
# ----------------------------
|
|
196
|
-
|
|
197
|
-
class RemoveTraceArtifact(StateChange):
|
|
198
|
-
"""Remove an existing trace artifact (TestTrace or LogTrace)."""
|
|
199
|
-
art_id: str = Field(description="Artifact ID")
|
|
200
|
-
|
|
201
|
-
def short_str(self) -> str:
|
|
202
|
-
return (
|
|
203
|
-
f"[bold deep_blue_sky]RemoveTraceArtifact[/bold deep_blue_sky]: "
|
|
204
|
-
f"[bold]ArtID[/bold]: {self.art_id}"
|
|
205
|
-
)
|
|
206
|
-
|
|
207
|
-
class AddTestTrace(StateChange):
|
|
208
|
-
"""Add a new TestTrace."""
|
|
209
|
-
art_id: str | None = Field(description="Artifact ID")
|
|
210
|
-
|
|
211
|
-
# TraceArtifact core
|
|
212
|
-
given: str = Field(description="Concrete state value (IML expression)")
|
|
213
|
-
when: Optional[str] = Field(default=None, description="Optional concrete action value (IML expression)")
|
|
214
|
-
then: Optional[str] = Field(default=None, description="Optional resulting state value (IML expression)")
|
|
215
|
-
time: str = Field(default="", description="Optional timestamp")
|
|
216
|
-
|
|
217
|
-
# TestTrace fields
|
|
218
|
-
name: str = Field(description="Test case name (not unique)")
|
|
219
|
-
filepath: str = Field(default="", description="Original test filepath")
|
|
220
|
-
language: Optional[str] = Field(default=None, description="Language of the original test source")
|
|
221
|
-
contents: Optional[str] = Field(default=None, description="Original test contents")
|
|
222
|
-
|
|
223
|
-
def short_str(self) -> str:
|
|
224
|
-
return (
|
|
225
|
-
f"[bold deep_blue_sky]AddTestTrace[/bold deep_blue_sky]: "
|
|
226
|
-
f"[bold]ArtID[/bold]: {self.art_id}"
|
|
227
|
-
)
|
|
228
|
-
|
|
229
|
-
class EditTestTrace(StateChange):
|
|
230
|
-
"""Edit an existing TestTrace (patch semantics: only non-None fields are applied)."""
|
|
231
|
-
art_id: str = Field(description="Artifact ID")
|
|
232
|
-
|
|
233
|
-
# TraceArtifact core (patch)
|
|
234
|
-
given: Optional[str] = Field(default=None, description="Concrete state value (IML expression)")
|
|
235
|
-
when: Optional[str] = Field(default=None, description="Optional concrete action value (IML expression)")
|
|
236
|
-
then: Optional[str] = Field(default=None, description="Optional resulting state value (IML expression)")
|
|
237
|
-
time: Optional[str] = Field(default=None, description="Optional timestamp")
|
|
238
|
-
|
|
239
|
-
# TestTrace fields (patch)
|
|
240
|
-
name: Optional[str] = Field(default=None, description="Test case name (not unique)")
|
|
241
|
-
filepath: Optional[str] = Field(default=None, description="Original test filepath")
|
|
242
|
-
language: Optional[str] = Field(default=None, description="Language of the original test source")
|
|
243
|
-
contents: Optional[str] = Field(default=None, description="Original test contents")
|
|
244
|
-
|
|
245
|
-
@model_validator(mode="after")
|
|
246
|
-
def _must_change_something(self) -> EditTestTrace:
|
|
247
|
-
if (
|
|
248
|
-
self.given is None
|
|
249
|
-
and self.when is None
|
|
250
|
-
and self.then is None
|
|
251
|
-
and self.time is None
|
|
252
|
-
and self.name is None
|
|
253
|
-
and self.filepath is None
|
|
254
|
-
and self.language is None
|
|
255
|
-
and self.contents is None
|
|
256
|
-
):
|
|
257
|
-
raise ValueError(
|
|
258
|
-
"EditTestTrace must provide at least one of: "
|
|
259
|
-
"given, when, then, time, name, filepath, language, or contents"
|
|
260
|
-
)
|
|
261
|
-
return self
|
|
262
|
-
|
|
263
|
-
def short_str(self) -> str:
|
|
264
|
-
return (
|
|
265
|
-
f"[bold deep_blue_sky]EditTestTrace[/bold deep_blue_sky]: "
|
|
266
|
-
f"[bold]ArtID[/bold]: {self.art_id}"
|
|
267
|
-
)
|
|
268
|
-
|
|
269
|
-
# ----------------------------
|
|
270
|
-
# Log traces
|
|
271
|
-
# ----------------------------
|
|
272
|
-
|
|
273
|
-
class AddLogTrace(StateChange):
|
|
274
|
-
"""Add a new LogTrace."""
|
|
275
|
-
art_id: str | None = Field(description="Artifact ID")
|
|
276
|
-
|
|
277
|
-
# TraceArtifact core
|
|
278
|
-
given: str = Field(description="Concrete state value (IML expression)")
|
|
279
|
-
when: Optional[str] = Field(default=None, description="Optional concrete action value (IML expression)")
|
|
280
|
-
then: Optional[str] = Field(default=None, description="Optional resulting state value (IML expression)")
|
|
281
|
-
time: str = Field(default="", description="Optional timestamp")
|
|
282
|
-
|
|
283
|
-
# LogTrace fields
|
|
284
|
-
filename: str = Field(description="Log filename (not unique)")
|
|
285
|
-
contents: str = Field(description="Log entry contents")
|
|
286
|
-
|
|
287
|
-
def short_str(self) -> str:
|
|
288
|
-
return (
|
|
289
|
-
f"[bold deep_blue_sky]AddLogTrace[/bold deep_blue_sky]: "
|
|
290
|
-
f"[bold]ArtID[/bold]: {self.art_id}"
|
|
291
|
-
)
|
|
292
|
-
|
|
293
|
-
class EditLogTrace(StateChange):
|
|
294
|
-
"""Edit an existing LogTrace (patch semantics: only non-None fields are applied)."""
|
|
295
|
-
art_id: str = Field(description="Artifact ID")
|
|
296
|
-
|
|
297
|
-
# TraceArtifact core (patch)
|
|
298
|
-
given: Optional[str] = Field(default=None, description="Concrete state value (IML expression)")
|
|
299
|
-
when: Optional[str] = Field(default=None, description="Optional concrete action value (IML expression)")
|
|
300
|
-
then: Optional[str] = Field(default=None, description="Optional resulting state value (IML expression)")
|
|
301
|
-
time: Optional[str] = Field(default=None, description="Optional timestamp")
|
|
302
|
-
|
|
303
|
-
# LogTrace fields (patch)
|
|
304
|
-
filename: Optional[str] = Field(default=None, description="Log filename (not unique)")
|
|
305
|
-
contents: Optional[str] = Field(default=None, description="Log entry contents")
|
|
306
|
-
|
|
307
|
-
@model_validator(mode="after")
|
|
308
|
-
def _must_change_something(self) -> EditLogTrace:
|
|
309
|
-
if (
|
|
310
|
-
self.given is None
|
|
311
|
-
and self.when is None
|
|
312
|
-
and self.then is None
|
|
313
|
-
and self.time is None
|
|
314
|
-
and self.filename is None
|
|
315
|
-
and self.contents is None
|
|
316
|
-
):
|
|
317
|
-
raise ValueError(
|
|
318
|
-
"EditLogTrace must provide at least one of: "
|
|
319
|
-
"given, when, then, time, filename, or contents"
|
|
320
|
-
)
|
|
321
|
-
return self
|
|
322
|
-
|
|
323
|
-
def short_str(self) -> str:
|
|
324
|
-
return (
|
|
325
|
-
f"[bold deep_blue_sky]EditLogTrace[/bold deep_blue_sky]: "
|
|
326
|
-
f"[bold]ArtID[/bold]: {self.art_id}"
|
|
327
|
-
)
|
|
328
|
-
|
|
329
|
-
# ----------------------------
|
|
330
|
-
# RemoveDataArtifact
|
|
331
|
-
# ----------------------------
|
|
332
|
-
|
|
333
|
-
class RemoveDataArtifact(StateChange):
|
|
334
|
-
""" Remove an existing data artifact """
|
|
335
|
-
art_id: str = Field(description="Artifact ID")
|
|
336
|
-
def short_str(self) -> str:
|
|
337
|
-
return "[bold deep_blue_sky]RemoveDataArtifact[/bold deep_blue_sky]"
|
|
338
|
-
|
|
339
|
-
# ----------------------------
|
|
340
|
-
# Documentation references
|
|
341
|
-
# ----------------------------
|
|
342
|
-
|
|
343
|
-
class AddDocRef(StateChange):
|
|
344
|
-
"""Add a new documentation reference artifact."""
|
|
345
|
-
art_id: str | None = Field(description="Artifact ID")
|
|
346
|
-
text: str = Field(description="Documentation text")
|
|
347
|
-
meta: str | None = Field(default=None, description="Optional metadata")
|
|
348
|
-
|
|
349
|
-
def short_str(self) -> str:
|
|
350
|
-
return f"[bold deep_blue_sky]AddDocRef[/bold deep_blue_sky]: [bold]ArtID[/bold]: {self.art_id}"
|
|
351
|
-
|
|
352
|
-
class EditDocRef(StateChange):
|
|
353
|
-
"""Edit an existing DocRef."""
|
|
354
|
-
art_id: str = Field(description="Artifact ID")
|
|
355
|
-
text: str | None = Field(default=None, description="New documentation text")
|
|
356
|
-
meta: str | None = Field(default=None, description="New metadata")
|
|
357
|
-
|
|
358
|
-
@model_validator(mode="after")
|
|
359
|
-
def _must_change_something(self) -> "EditDocRef":
|
|
360
|
-
if self.text is None and self.meta is None:
|
|
361
|
-
raise ValueError("EditDocRef must provide at least one of: text or meta")
|
|
362
|
-
return self
|
|
363
|
-
|
|
364
|
-
def short_str(self) -> str:
|
|
365
|
-
return f"[bold deep_blue_sky]EditDocRef[/bold deep_blue_sky]: [bold]ArtID[/bold]: {self.art_id}"
|
|
366
|
-
|
|
367
|
-
# ----------------------------
|
|
368
|
-
# Source code references
|
|
369
|
-
# ----------------------------
|
|
370
|
-
|
|
371
|
-
class AddSrcCodeRef(StateChange):
|
|
372
|
-
"""Add a new source code reference artifact."""
|
|
373
|
-
art_id: str | None = Field(description="Artifact ID")
|
|
374
|
-
src_code: str = Field(description="Source code")
|
|
375
|
-
language: str | None = Field(default=None, description="Programming language")
|
|
376
|
-
file_path: str | None = Field(default=None, description="Optional file path")
|
|
377
|
-
iml_code: str | None = Field(default=None, description="Optional IML formalization")
|
|
378
|
-
meta: str | None = Field(default=None, description="Optional metadata")
|
|
379
|
-
|
|
380
|
-
def short_str(self) -> str:
|
|
381
|
-
return f"[bold deep_blue_sky]AddSrcCodeRef[/bold deep_blue_sky]: [bold]ArtID[/bold]: {self.art_id}"
|
|
119
|
+
return f''
|
|
382
120
|
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
# Links in the ArtifactMap
|
|
412
|
-
# ----------------------------
|
|
413
|
-
|
|
414
|
-
class LinkArtifactsComponents(StateChange):
|
|
415
|
-
""" Add a link between a non-executable arifact (e.g. source code or documentation) and a model component """
|
|
416
|
-
art_id : str = Field(description="Artifact ID")
|
|
417
|
-
comp_name : str = Field(description="Component name")
|
|
418
|
-
|
|
419
|
-
def short_str(self) -> str:
|
|
420
|
-
return "[bold deep_blue_sky]LinkArtifactComponents[/bold deep_blue_sky]"
|
|
421
|
-
|
|
422
|
-
class RemoveArtComponentLink(StateChange):
|
|
423
|
-
""" Remove a link between a non-executable arifact (e.g. source code or documentation) and a model component """
|
|
424
|
-
art_id : str = Field(description="Artifact ID")
|
|
425
|
-
comp_name : str = Field(description="Component name")
|
|
426
|
-
|
|
427
|
-
def short_str(self) -> str:
|
|
428
|
-
return "[bold deep_blue_sky]RemoveArtComponentLink[/bold deep_blue_sky]"
|
|
121
|
+
def __str__(self):
|
|
122
|
+
return ''
|
|
123
|
+
|
|
124
|
+
class ScenarioRemoved(ModelChange):
|
|
125
|
+
"""
|
|
126
|
+
Remove a scenario
|
|
127
|
+
"""
|
|
128
|
+
scenario_name : str
|
|
129
|
+
|
|
130
|
+
def short_str(self):
|
|
131
|
+
return ''
|
|
132
|
+
|
|
133
|
+
def __str__(self):
|
|
134
|
+
return ""
|
|
135
|
+
|
|
136
|
+
if __name__ == "__main__":
|
|
137
|
+
|
|
138
|
+
from ..utils import console
|
|
139
|
+
|
|
140
|
+
console.print(ScenarioAdd(name="new_name"))
|
|
141
|
+
console.rule()
|
|
142
|
+
|
|
143
|
+
console.print(ScenarioEdit(scenario_name="hello"))
|
|
144
|
+
console.rule()
|
|
145
|
+
|
|
146
|
+
console.print(ScenarioRemoved(scenario_name=""))
|
|
147
|
+
console.rule()
|
|
148
|
+
|