imandrax-api-models 1.0.0__tar.gz
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.
- imandrax_api_models-1.0.0/PKG-INFO +15 -0
- imandrax_api_models-1.0.0/README.md +3 -0
- imandrax_api_models-1.0.0/pyproject.toml +93 -0
- imandrax_api_models-1.0.0/src/imandrax_api_models/__init__.py +93 -0
- imandrax_api_models-1.0.0/src/imandrax_api_models/decode_artifact_local.py +207 -0
- imandrax_api_models-1.0.0/src/imandrax_api_models/proto_models/__init__.py +83 -0
- imandrax_api_models-1.0.0/src/imandrax_api_models/proto_models/artmsg.py +30 -0
- imandrax_api_models-1.0.0/src/imandrax_api_models/proto_models/error.py +105 -0
- imandrax_api_models-1.0.0/src/imandrax_api_models/proto_models/locs.py +16 -0
- imandrax_api_models-1.0.0/src/imandrax_api_models/proto_models/session.py +27 -0
- imandrax_api_models-1.0.0/src/imandrax_api_models/proto_models/simple_api.py +411 -0
- imandrax_api_models-1.0.0/src/imandrax_api_models/proto_models/task.py +29 -0
- imandrax_api_models-1.0.0/src/imandrax_api_models/proto_models/utils.py +13 -0
- imandrax_api_models-1.0.0/src/imandrax_api_models/proto_utils.py +21 -0
- imandrax_api_models-1.0.0/src/imandrax_api_models/py.typed +0 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: imandrax-api-models
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Add your description here
|
|
5
|
+
Author: hongyu
|
|
6
|
+
Author-email: hongyu <hongyu@imandra.ai>
|
|
7
|
+
Requires-Dist: devtools>=0.12.2
|
|
8
|
+
Requires-Dist: imandrax-api[async]>=0.17.3.1
|
|
9
|
+
Requires-Dist: pydantic>=2.12.4
|
|
10
|
+
Requires-Python: >=3.12
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
|
|
13
|
+
# ImandraX API Models
|
|
14
|
+
|
|
15
|
+
Pydantic models for the ImandraX API.
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "imandrax-api-models"
|
|
3
|
+
version = "1.0.0"
|
|
4
|
+
description = "Add your description here"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
authors = [
|
|
7
|
+
{ name = "hongyu", email = "hongyu@imandra.ai" }
|
|
8
|
+
]
|
|
9
|
+
requires-python = ">=3.12"
|
|
10
|
+
dependencies = [
|
|
11
|
+
"devtools>=0.12.2",
|
|
12
|
+
"imandrax-api[async]>=0.17.3.1",
|
|
13
|
+
"pydantic>=2.12.4",
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
[build-system]
|
|
17
|
+
requires = ["uv_build>=0.8.22,<0.9.0"]
|
|
18
|
+
build-backend = "uv_build"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
[tool.uv.sources]
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
[[tool.uv.index]]
|
|
25
|
+
name = "testpypi"
|
|
26
|
+
url = "https://test.pypi.org/simple/"
|
|
27
|
+
publish-url = "https://test.pypi.org/legacy/"
|
|
28
|
+
explicit = true
|
|
29
|
+
|
|
30
|
+
[dependency-groups]
|
|
31
|
+
dev = [
|
|
32
|
+
"inline-snapshot[dirty-equals]>=0.31.1",
|
|
33
|
+
"ipykernel>=7.1.0",
|
|
34
|
+
"pytest>=9.0.1",
|
|
35
|
+
"pyyaml>=6.0.3",
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
[tool.ruff.lint]
|
|
39
|
+
extend-select = [
|
|
40
|
+
"Q",
|
|
41
|
+
"RUF100",
|
|
42
|
+
"RUF018", # https://docs.astral.sh/ruff/rules/assignment-in-assert/
|
|
43
|
+
"C90",
|
|
44
|
+
"UP",
|
|
45
|
+
"I",
|
|
46
|
+
"D",
|
|
47
|
+
"TID251",
|
|
48
|
+
]
|
|
49
|
+
flake8-quotes = { inline-quotes = "single", multiline-quotes = "double" }
|
|
50
|
+
mccabe = { max-complexity = 15 }
|
|
51
|
+
ignore = [
|
|
52
|
+
"D100", # ignore missing docstring in module
|
|
53
|
+
"D101", # ignore missing docstring in public class
|
|
54
|
+
"D102", # ignore missing docstring in public method
|
|
55
|
+
"D103", # ignore missing docstring in public function
|
|
56
|
+
"D104", # ignore missing docstring in public package
|
|
57
|
+
"D105", # ignore missing docstring in magic methods
|
|
58
|
+
"D106", # ignore missing docstring in public nested class
|
|
59
|
+
"D107", # ignore missing docstring in __init__ methods
|
|
60
|
+
"D203",
|
|
61
|
+
"D212",
|
|
62
|
+
]
|
|
63
|
+
pycodestyle.ignore-overlong-task-comments = true
|
|
64
|
+
isort.combine-as-imports = true
|
|
65
|
+
|
|
66
|
+
[tool.ruff.lint.per-file-ignores]
|
|
67
|
+
"scripts/**/*.py" = ["F401", "RUF100", "D", "E402", "B018"]
|
|
68
|
+
"data/**/*.py" = ["F401", "RUF100", "D", "E402", "B018"]
|
|
69
|
+
|
|
70
|
+
[tool.ruff.format]
|
|
71
|
+
quote-style = "single"
|
|
72
|
+
|
|
73
|
+
[tool.ty]
|
|
74
|
+
environment.python = "./.venv"
|
|
75
|
+
|
|
76
|
+
[tool.ty.rules]
|
|
77
|
+
# Handled by pyright
|
|
78
|
+
unsupported-operator = "ignore"
|
|
79
|
+
invalid-argument-type = "ignore"
|
|
80
|
+
invalid-return-type = "ignore"
|
|
81
|
+
possibly-missing-attribute = "ignore"
|
|
82
|
+
unresolved-import = "ignore"
|
|
83
|
+
|
|
84
|
+
[tool.pyright]
|
|
85
|
+
venvPath = "."
|
|
86
|
+
venv = ".venv"
|
|
87
|
+
pythonVersion = "3.12"
|
|
88
|
+
typeCheckingMode = "strict"
|
|
89
|
+
reportMissingTypeStubs = false
|
|
90
|
+
reportUnnecessaryIsInstance = false
|
|
91
|
+
reportUnnecessaryTypeIgnoreComment = true
|
|
92
|
+
reportUnusedImport = "none"
|
|
93
|
+
reportUnusedExpression = false
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
from .proto_models import (
|
|
2
|
+
Art,
|
|
3
|
+
CounterSat,
|
|
4
|
+
DecomposeReq,
|
|
5
|
+
DecomposeRes,
|
|
6
|
+
Empty,
|
|
7
|
+
Error,
|
|
8
|
+
ErrorKind,
|
|
9
|
+
ErrorMessage,
|
|
10
|
+
EvalOutput,
|
|
11
|
+
EvalRes,
|
|
12
|
+
EvalSrcReq,
|
|
13
|
+
InferredType,
|
|
14
|
+
InstanceNameReq,
|
|
15
|
+
InstanceRes,
|
|
16
|
+
InstanceSrcReq,
|
|
17
|
+
LiftBool,
|
|
18
|
+
Location,
|
|
19
|
+
Model,
|
|
20
|
+
ModelType,
|
|
21
|
+
OneshotReq,
|
|
22
|
+
OneshotRes,
|
|
23
|
+
Origin,
|
|
24
|
+
PO_Res,
|
|
25
|
+
Position,
|
|
26
|
+
Proved,
|
|
27
|
+
Refuted,
|
|
28
|
+
RegionStr,
|
|
29
|
+
Sat,
|
|
30
|
+
Session,
|
|
31
|
+
SessionCreate,
|
|
32
|
+
SessionCreateReq,
|
|
33
|
+
SessionOpen,
|
|
34
|
+
StorageEntry,
|
|
35
|
+
StringMsg,
|
|
36
|
+
Task,
|
|
37
|
+
TaskID,
|
|
38
|
+
TaskKind,
|
|
39
|
+
TypecheckReq,
|
|
40
|
+
TypecheckRes,
|
|
41
|
+
Unsat,
|
|
42
|
+
Verified_upto,
|
|
43
|
+
VerifyNameReq,
|
|
44
|
+
VerifyRes,
|
|
45
|
+
VerifySrcReq,
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
__all__ = [
|
|
49
|
+
'Art',
|
|
50
|
+
'CounterSat',
|
|
51
|
+
'DecomposeReq',
|
|
52
|
+
'DecomposeRes',
|
|
53
|
+
'Empty',
|
|
54
|
+
'Error',
|
|
55
|
+
'ErrorKind',
|
|
56
|
+
'ErrorMessage',
|
|
57
|
+
'EvalOutput',
|
|
58
|
+
'EvalRes',
|
|
59
|
+
'EvalSrcReq',
|
|
60
|
+
'InferredType',
|
|
61
|
+
'InstanceNameReq',
|
|
62
|
+
'InstanceRes',
|
|
63
|
+
'InstanceSrcReq',
|
|
64
|
+
'LiftBool',
|
|
65
|
+
'Location',
|
|
66
|
+
'Model',
|
|
67
|
+
'ModelType',
|
|
68
|
+
'OneshotReq',
|
|
69
|
+
'OneshotRes',
|
|
70
|
+
'Origin',
|
|
71
|
+
'PO_Res',
|
|
72
|
+
'Position',
|
|
73
|
+
'Proved',
|
|
74
|
+
'Refuted',
|
|
75
|
+
'RegionStr',
|
|
76
|
+
'Sat',
|
|
77
|
+
'Session',
|
|
78
|
+
'SessionCreate',
|
|
79
|
+
'SessionCreateReq',
|
|
80
|
+
'SessionOpen',
|
|
81
|
+
'StorageEntry',
|
|
82
|
+
'StringMsg',
|
|
83
|
+
'Task',
|
|
84
|
+
'TaskID',
|
|
85
|
+
'TaskKind',
|
|
86
|
+
'TypecheckReq',
|
|
87
|
+
'TypecheckRes',
|
|
88
|
+
'Unsat',
|
|
89
|
+
'Verified_upto',
|
|
90
|
+
'VerifyNameReq',
|
|
91
|
+
'VerifyRes',
|
|
92
|
+
'VerifySrcReq',
|
|
93
|
+
]
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import base64
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from typing import Any, assert_never
|
|
6
|
+
|
|
7
|
+
from imandrax_api.lib import (
|
|
8
|
+
Artifact,
|
|
9
|
+
Common_Applied_symbol_t_poly,
|
|
10
|
+
Common_Fun_decomp_t_poly,
|
|
11
|
+
Common_Model_t_poly,
|
|
12
|
+
Common_Region_meta_Assoc,
|
|
13
|
+
Common_Region_meta_String,
|
|
14
|
+
Common_Region_meta_Term,
|
|
15
|
+
Common_Region_t_poly,
|
|
16
|
+
Common_Var_t_poly,
|
|
17
|
+
Mir_Fun_decomp,
|
|
18
|
+
Mir_Term,
|
|
19
|
+
Mir_Term_view_Const,
|
|
20
|
+
Mir_Term_view_Construct,
|
|
21
|
+
Mir_Type,
|
|
22
|
+
Uid,
|
|
23
|
+
read_artifact_data,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@dataclass
|
|
28
|
+
class RegionStr:
|
|
29
|
+
constraints_str: list[str] | None
|
|
30
|
+
invariant_str: str
|
|
31
|
+
model_str: dict[str, str]
|
|
32
|
+
model_eval_str: str | None
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class ArtifactDecodeError(Exception):
|
|
36
|
+
pass
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def decode_artifact(
|
|
40
|
+
data: bytes | str,
|
|
41
|
+
kind: str,
|
|
42
|
+
) -> list[RegionStr] | dict[str, str] | None:
|
|
43
|
+
data_b: bytes = base64.b64decode(data) if isinstance(data, str) else data
|
|
44
|
+
art: Artifact = read_artifact_data(data=data_b, kind=kind)
|
|
45
|
+
match (art, kind):
|
|
46
|
+
case (
|
|
47
|
+
Common_Fun_decomp_t_poly(
|
|
48
|
+
f_id=_f_id,
|
|
49
|
+
f_args=_f_args,
|
|
50
|
+
regions=regions,
|
|
51
|
+
) as _fun_decomp,
|
|
52
|
+
'mir.fun_decomp',
|
|
53
|
+
):
|
|
54
|
+
_fun_decomp: Mir_Fun_decomp
|
|
55
|
+
_f_id: Uid
|
|
56
|
+
_f_args: list[Common_Var_t_poly[Mir_Type]]
|
|
57
|
+
regions: list[Common_Region_t_poly[Mir_Term, Mir_Type]]
|
|
58
|
+
|
|
59
|
+
return unwrap_region_str(regions)
|
|
60
|
+
case (
|
|
61
|
+
Common_Model_t_poly(
|
|
62
|
+
# list[tuple[Mir_Type, Common_Model_ty_def[Mir_Term, Mir_Type]]]
|
|
63
|
+
tys=_,
|
|
64
|
+
consts=consts,
|
|
65
|
+
# list[
|
|
66
|
+
# tuple[
|
|
67
|
+
# Common_Applied_symbol_t_poly[Mir_Type],
|
|
68
|
+
# Common_Model_fi[Mir_Term, Mir_Type],
|
|
69
|
+
# ]
|
|
70
|
+
# ]
|
|
71
|
+
funs=_,
|
|
72
|
+
# bool
|
|
73
|
+
representable=_,
|
|
74
|
+
# bool
|
|
75
|
+
completed=_,
|
|
76
|
+
# list[tuple[Uid, Mir_Type]]
|
|
77
|
+
ty_subst=_,
|
|
78
|
+
) as _mir_model,
|
|
79
|
+
'mir.model',
|
|
80
|
+
):
|
|
81
|
+
consts: list[tuple[Common_Applied_symbol_t_poly[Mir_Type], Mir_Term]]
|
|
82
|
+
consts_d: dict[str, Any] = unwrap_model_constants(consts)
|
|
83
|
+
return consts_d
|
|
84
|
+
case _:
|
|
85
|
+
raise ArtifactDecodeError(
|
|
86
|
+
f'Unknown artifact type: {type(art)}, with {kind = }'
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def unwrap_model_constants(
|
|
91
|
+
consts: list[tuple[Common_Applied_symbol_t_poly[Mir_Type], Mir_Term]],
|
|
92
|
+
) -> dict[str, Any]:
|
|
93
|
+
constants: dict[str, Any] = {}
|
|
94
|
+
|
|
95
|
+
for applied_symbol, term in consts:
|
|
96
|
+
match applied_symbol, term:
|
|
97
|
+
case (
|
|
98
|
+
Common_Applied_symbol_t_poly(
|
|
99
|
+
sym=applied_symbol_sym,
|
|
100
|
+
args=_,
|
|
101
|
+
ty=_,
|
|
102
|
+
),
|
|
103
|
+
Mir_Term(view=term_view, ty=_, sub_anchor=_),
|
|
104
|
+
):
|
|
105
|
+
var_name = applied_symbol_sym.id.name
|
|
106
|
+
|
|
107
|
+
# Extract the value from the term
|
|
108
|
+
match term_view:
|
|
109
|
+
case Mir_Term_view_Const(arg=term_view_const):
|
|
110
|
+
constants[var_name] = term_view_const.arg
|
|
111
|
+
case Mir_Term_view_Construct():
|
|
112
|
+
raise NotImplementedError(
|
|
113
|
+
'Term view type of Mir_Term_view_Construct is not supported'
|
|
114
|
+
)
|
|
115
|
+
case _:
|
|
116
|
+
raise NotImplementedError(
|
|
117
|
+
f'Unexpected term view type: {type(term_view)}'
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
return constants
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
type region_meta_value = (
|
|
124
|
+
Common_Region_meta_Assoc[Mir_Term]
|
|
125
|
+
| Common_Region_meta_Term[Mir_Term]
|
|
126
|
+
| Common_Region_meta_String[Mir_Term]
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def unwrap_region_str(
|
|
131
|
+
regions: list[Common_Region_t_poly[Mir_Term, Mir_Type]],
|
|
132
|
+
) -> list[RegionStr]:
|
|
133
|
+
"""
|
|
134
|
+
Get `RegionStr`s from a list of `Region.t`.
|
|
135
|
+
|
|
136
|
+
A region object looks like:
|
|
137
|
+
{
|
|
138
|
+
"constraints": [...],
|
|
139
|
+
"invariant": ...,
|
|
140
|
+
"meta": [
|
|
141
|
+
("str", ...) # What we want
|
|
142
|
+
("model", ...)
|
|
143
|
+
("model_eval", ...)
|
|
144
|
+
("id", "...")
|
|
145
|
+
]
|
|
146
|
+
"status": ...
|
|
147
|
+
}.
|
|
148
|
+
"""
|
|
149
|
+
regions_str: list[RegionStr] = []
|
|
150
|
+
for region in regions:
|
|
151
|
+
match region:
|
|
152
|
+
case Common_Region_t_poly(
|
|
153
|
+
constraints=_constraints,
|
|
154
|
+
invariant=_invariant,
|
|
155
|
+
meta=meta,
|
|
156
|
+
status=_status,
|
|
157
|
+
):
|
|
158
|
+
# Convert meta list to dict
|
|
159
|
+
meta_d: dict[Any, Any] = dict(meta)
|
|
160
|
+
|
|
161
|
+
# get `str` dict
|
|
162
|
+
meta_str_raw = meta_d.get('str')
|
|
163
|
+
assert meta_str_raw is not None, "Never: no 'str' in meta"
|
|
164
|
+
|
|
165
|
+
# meta_str should be Common_Region_meta_Assoc[Mir_Term]
|
|
166
|
+
if not isinstance(meta_str_raw, Common_Region_meta_Assoc):
|
|
167
|
+
raise ValueError(
|
|
168
|
+
f'Expected Common_Region_meta_Assoc, got {type(meta_str_raw)}'
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
meta_str_d: dict[Any, Any] = dict(meta_str_raw.arg) # type: ignore[arg-type]
|
|
172
|
+
|
|
173
|
+
# Extract constraints
|
|
174
|
+
constraints_raw = meta_str_d.get('constraints')
|
|
175
|
+
constraints: list[str] | None
|
|
176
|
+
if constraints_raw is not None:
|
|
177
|
+
constraints = [c.arg for c in constraints_raw.arg]
|
|
178
|
+
else:
|
|
179
|
+
constraints = None
|
|
180
|
+
|
|
181
|
+
# Extract invariant
|
|
182
|
+
invariant_raw = meta_str_d.get('invariant')
|
|
183
|
+
invariant: str = invariant_raw.arg if invariant_raw is not None else ''
|
|
184
|
+
|
|
185
|
+
# Extract model
|
|
186
|
+
model_raw = meta_str_d.get('model')
|
|
187
|
+
model: dict[str, str] = {}
|
|
188
|
+
if model_raw is not None:
|
|
189
|
+
model = {k: v.arg for (k, v) in model_raw.arg}
|
|
190
|
+
|
|
191
|
+
# Extract model_eval (optional)
|
|
192
|
+
model_eval: str | None = None
|
|
193
|
+
if 'model_eval' in meta_str_d:
|
|
194
|
+
model_eval_raw = meta_str_d['model_eval']
|
|
195
|
+
if model_eval_raw is not None:
|
|
196
|
+
model_eval = model_eval_raw.arg
|
|
197
|
+
|
|
198
|
+
region_str = RegionStr(
|
|
199
|
+
invariant_str=invariant,
|
|
200
|
+
constraints_str=constraints,
|
|
201
|
+
model_str=model,
|
|
202
|
+
model_eval_str=model_eval,
|
|
203
|
+
)
|
|
204
|
+
regions_str.append(region_str)
|
|
205
|
+
case _:
|
|
206
|
+
assert_never(region)
|
|
207
|
+
return regions_str
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
from .artmsg import Art, StorageEntry
|
|
2
|
+
from .error import Error, ErrorKind, ErrorMessage
|
|
3
|
+
from .locs import Location, Position
|
|
4
|
+
from .session import Session, SessionCreate, SessionOpen
|
|
5
|
+
from .simple_api import (
|
|
6
|
+
CounterSat,
|
|
7
|
+
DecomposeReq,
|
|
8
|
+
DecomposeRes,
|
|
9
|
+
EvalOutput,
|
|
10
|
+
EvalRes,
|
|
11
|
+
EvalSrcReq,
|
|
12
|
+
InferredType,
|
|
13
|
+
InstanceNameReq,
|
|
14
|
+
InstanceRes,
|
|
15
|
+
InstanceSrcReq,
|
|
16
|
+
LiftBool,
|
|
17
|
+
Model,
|
|
18
|
+
ModelType,
|
|
19
|
+
OneshotReq,
|
|
20
|
+
OneshotRes,
|
|
21
|
+
PO_Res,
|
|
22
|
+
Proved,
|
|
23
|
+
Refuted,
|
|
24
|
+
RegionStr,
|
|
25
|
+
Sat,
|
|
26
|
+
SessionCreateReq,
|
|
27
|
+
TypecheckReq,
|
|
28
|
+
TypecheckRes,
|
|
29
|
+
Unsat,
|
|
30
|
+
Verified_upto,
|
|
31
|
+
VerifyNameReq,
|
|
32
|
+
VerifyRes,
|
|
33
|
+
VerifySrcReq,
|
|
34
|
+
)
|
|
35
|
+
from .task import Origin, Task, TaskID, TaskKind
|
|
36
|
+
from .utils import Empty, StringMsg
|
|
37
|
+
|
|
38
|
+
__all__ = [
|
|
39
|
+
'Art',
|
|
40
|
+
'CounterSat',
|
|
41
|
+
'DecomposeReq',
|
|
42
|
+
'DecomposeRes',
|
|
43
|
+
'Empty',
|
|
44
|
+
'Error',
|
|
45
|
+
'ErrorKind',
|
|
46
|
+
'ErrorMessage',
|
|
47
|
+
'EvalOutput',
|
|
48
|
+
'EvalRes',
|
|
49
|
+
'EvalSrcReq',
|
|
50
|
+
'InferredType',
|
|
51
|
+
'InstanceNameReq',
|
|
52
|
+
'InstanceRes',
|
|
53
|
+
'InstanceSrcReq',
|
|
54
|
+
'LiftBool',
|
|
55
|
+
'Location',
|
|
56
|
+
'Model',
|
|
57
|
+
'ModelType',
|
|
58
|
+
'OneshotReq',
|
|
59
|
+
'OneshotRes',
|
|
60
|
+
'Origin',
|
|
61
|
+
'PO_Res',
|
|
62
|
+
'Position',
|
|
63
|
+
'Proved',
|
|
64
|
+
'Refuted',
|
|
65
|
+
'RegionStr',
|
|
66
|
+
'Sat',
|
|
67
|
+
'Session',
|
|
68
|
+
'SessionCreate',
|
|
69
|
+
'SessionCreateReq',
|
|
70
|
+
'SessionOpen',
|
|
71
|
+
'StorageEntry',
|
|
72
|
+
'StringMsg',
|
|
73
|
+
'Task',
|
|
74
|
+
'TaskID',
|
|
75
|
+
'TaskKind',
|
|
76
|
+
'TypecheckReq',
|
|
77
|
+
'TypecheckRes',
|
|
78
|
+
'Unsat',
|
|
79
|
+
'Verified_upto',
|
|
80
|
+
'VerifyNameReq',
|
|
81
|
+
'VerifyRes',
|
|
82
|
+
'VerifySrcReq',
|
|
83
|
+
]
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pydantic import ConfigDict, Field
|
|
4
|
+
|
|
5
|
+
from ..proto_utils import BaseModel
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class StorageEntry(BaseModel):
|
|
9
|
+
model_config = ConfigDict(ser_json_bytes='base64', val_json_bytes='base64')
|
|
10
|
+
|
|
11
|
+
key: str = Field(description='the CA store key')
|
|
12
|
+
value: bytes = Field(description='the stored value')
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# We tend to generate this using `google.protobuf.json_format.MessageToDict`
|
|
16
|
+
# This converts protobuf bytes to base64 strings
|
|
17
|
+
class Art(BaseModel):
|
|
18
|
+
model_config = ConfigDict(ser_json_bytes='base64', val_json_bytes='base64')
|
|
19
|
+
|
|
20
|
+
kind: str = Field(description='The kind of artifact')
|
|
21
|
+
data: bytes = Field(description='Serialized data, in twine')
|
|
22
|
+
api_version: str = Field(
|
|
23
|
+
description=(
|
|
24
|
+
'Version of the API. This is mandatory and must match with the imandrax-api'
|
|
25
|
+
' library version.'
|
|
26
|
+
)
|
|
27
|
+
)
|
|
28
|
+
storage: list[StorageEntry] = Field(
|
|
29
|
+
default_factory=lambda: [], description='Additional definitions on the side'
|
|
30
|
+
)
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
from enum import Enum
|
|
5
|
+
from typing import Self
|
|
6
|
+
|
|
7
|
+
from pydantic import Field
|
|
8
|
+
|
|
9
|
+
from ..proto_utils import BaseModel
|
|
10
|
+
from .locs import Location
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# from https://github.com/imandra-ai/imandrax-api/blob/1a4abb4eb59d9545c6f0af9698956437b5b5dcb8/src/internal/error_data/imandrax_errors.ml
|
|
14
|
+
class ErrorKind(str, Enum):
|
|
15
|
+
APPLIED_SYMBOL_TYPE_ERR = 'AppliedSymbolTypeErr'
|
|
16
|
+
CONFIG_ERROR = 'ConfigError'
|
|
17
|
+
CPTR_GET_OTHER_ERR = 'CptrGetOtherErr'
|
|
18
|
+
CPTR_NOT_FOUND_IN_STORAGE = 'CptrNotFoundInStorage'
|
|
19
|
+
GENERIC_USER_ERROR = 'GenericUserError'
|
|
20
|
+
INVALID_FUN_DEFINITION = 'InvalidFunDefinition'
|
|
21
|
+
INVALID_QIDENT = 'InvalidQident'
|
|
22
|
+
INVALID_TYPE_ALIAS = 'InvalidTypeAlias'
|
|
23
|
+
INVALID_TYPE_DEFINITION = 'InvalidTypeDefinition'
|
|
24
|
+
INVALID_CNAME = 'InvalidCname'
|
|
25
|
+
LEVAL_ERROR = 'LevalError'
|
|
26
|
+
LOWER_CIR_ERROR = 'LowerCirError'
|
|
27
|
+
LOWER_MIR_ERROR = 'LowerMirError'
|
|
28
|
+
LOWER_RIR_ERROR = 'LowerRirError'
|
|
29
|
+
PARSER_NOT_REGISTERED = 'ParserNotRegistered'
|
|
30
|
+
PATMATCH_ERROR = 'PatmatchError'
|
|
31
|
+
SYN_TERM_CREATE_ERROR = 'SynTermCreateError'
|
|
32
|
+
SYNTAX_ATTRIBUTE_ERR = 'SyntaxAttributeErr'
|
|
33
|
+
SYNTAX_ERR = 'SyntaxErr'
|
|
34
|
+
SYNTAX_UNSUGAR_ERR = 'SyntaxUnsugarErr'
|
|
35
|
+
TACTIC_EVAL_ERR = 'TacticEvalErr'
|
|
36
|
+
TERM_INVALID_SHAPE = 'TermInvalidShape'
|
|
37
|
+
TERM_MODEL_FIERR = 'TermModelFIErr'
|
|
38
|
+
THREAD_FUT_FAILURE = 'ThreadFutFailure'
|
|
39
|
+
THREAD_TIMER_FAILURE = 'ThreadTimerFailure'
|
|
40
|
+
TY_INFER_INTERNAL_ERROR = 'TyInferInternalError'
|
|
41
|
+
TYPE_ARITY_MISMATCH = 'TypeArityMismatch'
|
|
42
|
+
TYPE_CYCLE_DETECTED = 'TypeCycleDetected'
|
|
43
|
+
TYPE_ERR = 'TypeErr'
|
|
44
|
+
TYPE_VAR_ALREADY_BOUND = 'TypeVarAlreadyBound'
|
|
45
|
+
TYPED_SYMBOL_NON_GROUND = 'TypedSymbolNonGround'
|
|
46
|
+
UID_CONTENT_ADDRESSING_NAME_MISMATCH = 'UidContentAddressingNameMismatch'
|
|
47
|
+
UID_CONTENT_ADDRESSING_NOT_TEMPORARY = 'UidContentAddressingNotTemporary'
|
|
48
|
+
UID_NOT_CONTENT_ADDRESSED = 'UidNotContentAddressed'
|
|
49
|
+
UNKNOWN_BUILTIN_SYMBOL_FOR_UID = 'UnknownBuiltinSymbolForUid'
|
|
50
|
+
UNKNOWN_TYPE_DEFINITION = 'UnknownTypeDefinition'
|
|
51
|
+
INTERACTIVE_PROOF_ERR = 'InteractiveProofErr'
|
|
52
|
+
PROOF_DESER_ERROR = 'ProofDeserError'
|
|
53
|
+
PROOF_CHECK_ERROR = 'ProofCheckError'
|
|
54
|
+
INVALID_ANCHOR = 'InvalidAnchor'
|
|
55
|
+
INDUCT_SCHEMA_ERROR = 'InductSchemaError'
|
|
56
|
+
UNSUPPORTED = 'Unsupported'
|
|
57
|
+
LOWER_FOL_ERROR = 'LowerFolError'
|
|
58
|
+
VALIDATION_ERROR = 'ValidationError'
|
|
59
|
+
LSP_ERROR = 'LspError'
|
|
60
|
+
INTERRUPTED = 'Interrupted'
|
|
61
|
+
REDIS_ERROR = 'RedisError'
|
|
62
|
+
CIRDECL_NOT_FOUND_IN_STORAGE = 'CIRDeclNotFoundInStorage'
|
|
63
|
+
SERIALIZATION_ERROR = 'SerializationError'
|
|
64
|
+
DESERIALIZATION_ERROR = 'DeserializationError'
|
|
65
|
+
DEBUG_MODE = 'DebugMode'
|
|
66
|
+
IMPORT_ERROR = 'ImportError'
|
|
67
|
+
GENERIC_IOERROR = 'GenericIOError'
|
|
68
|
+
DUNE_ERROR = 'DuneError'
|
|
69
|
+
RPC_ERROR = 'RpcError'
|
|
70
|
+
RPC_DESER_ERROR = 'RpcDeserError'
|
|
71
|
+
RPC_NETWORK_ERROR = 'RpcNetworkError'
|
|
72
|
+
RPC_TIMEOUT = 'RpcTimeout'
|
|
73
|
+
AUTH_ERROR = 'AuthError'
|
|
74
|
+
FILE_EXISTS = 'FileExists'
|
|
75
|
+
DIRECTORY_CREATION_ERROR = 'DirectoryCreationError'
|
|
76
|
+
DECOMP_ERROR = 'DecompError'
|
|
77
|
+
VERSION_MISMATCH_ERROR = 'VersionMismatchError'
|
|
78
|
+
OH_NO_ERROR = 'OhNoError'
|
|
79
|
+
DEBOUNCED = 'Debounced'
|
|
80
|
+
|
|
81
|
+
@classmethod
|
|
82
|
+
def from_proto_kind(cls, proto_kind: str) -> Self:
|
|
83
|
+
kinds = re.findall(r'\{ Kind.name = "(.+)" \}', proto_kind)
|
|
84
|
+
if len(kinds) != 1:
|
|
85
|
+
raise ValueError('Unable to parse kind')
|
|
86
|
+
return cls(kinds[0])
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class ErrorMessage(BaseModel):
|
|
90
|
+
msg: str
|
|
91
|
+
locs: list[Location] = Field(
|
|
92
|
+
default_factory=lambda: [], description='Locations for this message'
|
|
93
|
+
)
|
|
94
|
+
backtrace: str | None = Field(default=None, description='Captured backtrace')
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class Error(BaseModel):
|
|
98
|
+
msg: ErrorMessage | None = Field(
|
|
99
|
+
default=None, description='The toplevel error message'
|
|
100
|
+
)
|
|
101
|
+
kind: str = Field(description='A string description of the kind of error')
|
|
102
|
+
stack: list[ErrorMessage] = Field(
|
|
103
|
+
default_factory=lambda: [], description='Context for the error'
|
|
104
|
+
)
|
|
105
|
+
process: str | None = Field(default=None)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pydantic import Field
|
|
4
|
+
|
|
5
|
+
from ..proto_utils import BaseModel
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Position(BaseModel):
|
|
9
|
+
line: int
|
|
10
|
+
col: int
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Location(BaseModel):
|
|
14
|
+
file: str | None = Field(default=None)
|
|
15
|
+
start: Position | None = Field(default=None)
|
|
16
|
+
stop: Position | None = Field(default=None)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pydantic import Field
|
|
4
|
+
|
|
5
|
+
from ..proto_utils import BaseModel
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Session(BaseModel):
|
|
9
|
+
"""A session identifier."""
|
|
10
|
+
|
|
11
|
+
id: str = Field(description="The session's unique ID (e.g a uuid)")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class SessionCreate(BaseModel):
|
|
15
|
+
"""Create a new session."""
|
|
16
|
+
|
|
17
|
+
po_check: bool = Field(default=True, description='Do we check Proof Obligations?')
|
|
18
|
+
api_version: str = Field(description='the API types version (mandatory)')
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class SessionOpen(BaseModel):
|
|
22
|
+
"""Reconnect to the given session."""
|
|
23
|
+
|
|
24
|
+
id: Session | None = Field(
|
|
25
|
+
default=None, description="The session's unique ID (e.g a uuid)"
|
|
26
|
+
)
|
|
27
|
+
api_version: str = Field(description='the API types version (mandatory)')
|
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from enum import Enum
|
|
4
|
+
from typing import Any, Literal, Self
|
|
5
|
+
|
|
6
|
+
from devtools import pformat
|
|
7
|
+
from imandrax_api.lib import (
|
|
8
|
+
RegionStr,
|
|
9
|
+
get_region_str_from_decomp_artifact,
|
|
10
|
+
)
|
|
11
|
+
from pydantic import (
|
|
12
|
+
Field,
|
|
13
|
+
TypeAdapter,
|
|
14
|
+
field_validator,
|
|
15
|
+
model_validator,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
from ..proto_utils import BaseModel
|
|
19
|
+
from .artmsg import Art
|
|
20
|
+
from .error import Error
|
|
21
|
+
from .session import Session
|
|
22
|
+
from .task import Origin, Task
|
|
23
|
+
from .utils import Empty, StringMsg
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class SessionCreateReq(BaseModel):
|
|
27
|
+
api_version: str = Field(description='the API types version (mandatory)')
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class LiftBool(Enum):
|
|
31
|
+
Default = 0
|
|
32
|
+
NestedEqualities = 1
|
|
33
|
+
Equalities = 2
|
|
34
|
+
All = 3
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class DecomposeReq(BaseModel):
|
|
38
|
+
session: Session | None = Field(default=None)
|
|
39
|
+
name: str = Field(description='name of function to decompose')
|
|
40
|
+
assuming: str | None = Field(
|
|
41
|
+
default=None, description='name of side condition function'
|
|
42
|
+
)
|
|
43
|
+
basis: list[str]
|
|
44
|
+
rule_specs: list[str]
|
|
45
|
+
prune: bool
|
|
46
|
+
ctx_simp: bool | None = Field(default=None)
|
|
47
|
+
lift_bool: LiftBool | None = Field(default=None)
|
|
48
|
+
str_: bool = Field(default=True, alias='str')
|
|
49
|
+
timeout: int | None = Field(default=None)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class DecomposeResProto(BaseModel):
|
|
53
|
+
artifact: Art | None = Field(default=None)
|
|
54
|
+
err: Empty | None = Field(default=None)
|
|
55
|
+
errors: list[Error] = Field(default_factory=lambda: [])
|
|
56
|
+
task: Task | None = Field(default=None)
|
|
57
|
+
|
|
58
|
+
@model_validator(mode='after')
|
|
59
|
+
def one_of_res(self) -> Self:
|
|
60
|
+
if (self.artifact is None) == (self.err is None):
|
|
61
|
+
raise ValueError('One of artifact or err must be set')
|
|
62
|
+
return self
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class string_kv(BaseModel):
|
|
66
|
+
k: str
|
|
67
|
+
v: str
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class DecomposeRes(DecomposeResProto):
|
|
71
|
+
"""Result of a decomposition."""
|
|
72
|
+
|
|
73
|
+
regions_str: list[RegionStr] | None = Field(
|
|
74
|
+
default=None, description="None if there's decomposition error"
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
@model_validator(mode='after')
|
|
78
|
+
def unwrap_region_str(self) -> Self:
|
|
79
|
+
if self.regions_str is not None:
|
|
80
|
+
return self
|
|
81
|
+
elif self.errors:
|
|
82
|
+
return self
|
|
83
|
+
else:
|
|
84
|
+
assert self.artifact is not None, 'artifact must be present when no errors'
|
|
85
|
+
regions_str = get_region_str_from_decomp_artifact(
|
|
86
|
+
data=self.artifact.data, kind=self.artifact.kind
|
|
87
|
+
)
|
|
88
|
+
return self.model_copy(update={'regions_str': regions_str})
|
|
89
|
+
|
|
90
|
+
def __repr__(self) -> str:
|
|
91
|
+
return pformat(self)
|
|
92
|
+
|
|
93
|
+
@property
|
|
94
|
+
def iml_test_cases(self) -> list[dict[str, Any]]:
|
|
95
|
+
"""
|
|
96
|
+
Format region strings as test cases.
|
|
97
|
+
|
|
98
|
+
Eg: [
|
|
99
|
+
{"args": {"x": "1", "y": "2"}, "expected_output": "3"},
|
|
100
|
+
{"args": {"x": "3", "y": "4"}, "expected_output": "7"},
|
|
101
|
+
].
|
|
102
|
+
"""
|
|
103
|
+
if not self.regions_str:
|
|
104
|
+
return []
|
|
105
|
+
test_cases: list[dict[str, Any]] = []
|
|
106
|
+
for region_str in self.regions_str:
|
|
107
|
+
if (model_eval_str := region_str.model_eval_str) is None:
|
|
108
|
+
continue
|
|
109
|
+
test_cases.append(
|
|
110
|
+
{'args': region_str.model_str, 'expected_output': model_eval_str}
|
|
111
|
+
)
|
|
112
|
+
return test_cases
|
|
113
|
+
|
|
114
|
+
@property
|
|
115
|
+
def test_docstrs(self) -> list[str]:
|
|
116
|
+
docstrs: list[str] = []
|
|
117
|
+
if not self.regions_str:
|
|
118
|
+
return docstrs
|
|
119
|
+
for region_str in self.regions_str:
|
|
120
|
+
s = ''
|
|
121
|
+
if region_str.constraints_str:
|
|
122
|
+
s += 'Constraints:\n'
|
|
123
|
+
for c in region_str.constraints_str:
|
|
124
|
+
s += f' - `{c}`\n'
|
|
125
|
+
if region_str.invariant_str:
|
|
126
|
+
s += 'Invariant:\n'
|
|
127
|
+
s += f' - `{region_str.invariant_str}`\n'
|
|
128
|
+
docstrs.append(s)
|
|
129
|
+
return docstrs
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
class EvalSrcReq(BaseModel):
|
|
133
|
+
session: Session | None = Field(default=None)
|
|
134
|
+
src: str = Field(description='source code to evaluate')
|
|
135
|
+
async_only: bool | None = Field(
|
|
136
|
+
default=None,
|
|
137
|
+
description='if true, do not wait for tasks results, only return the task list '
|
|
138
|
+
'and not the task results. Use `get_artifact` to get the results.',
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
class EvalOutput(BaseModel):
|
|
143
|
+
"""Output of an `eval` statement."""
|
|
144
|
+
|
|
145
|
+
success: bool
|
|
146
|
+
value_as_ocaml: str | None = Field(
|
|
147
|
+
default=None, description='result as a OCaml value, if any'
|
|
148
|
+
)
|
|
149
|
+
errors: list[Error] = Field(default_factory=lambda: [])
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
class EvalRes(BaseModel):
|
|
153
|
+
success: bool = Field()
|
|
154
|
+
messages: list[str] = Field(
|
|
155
|
+
default_factory=lambda: [], description='"normal" messages'
|
|
156
|
+
)
|
|
157
|
+
errors: list[Error] = Field(
|
|
158
|
+
default_factory=lambda: [], description='akin to stderr'
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
# All tasks started during eval
|
|
162
|
+
tasks: list[Task] = Field(
|
|
163
|
+
default_factory=lambda: [], description='all tasks started during eval'
|
|
164
|
+
)
|
|
165
|
+
po_results: list[PO_Res] = Field(default_factory=lambda: [])
|
|
166
|
+
eval_results: list[EvalOutput] = Field(default_factory=lambda: [])
|
|
167
|
+
decomp_results: list[DecomposeRes] = Field(default_factory=lambda: [])
|
|
168
|
+
|
|
169
|
+
def __repr__(self) -> str:
|
|
170
|
+
return pformat(self, indent=2)
|
|
171
|
+
|
|
172
|
+
@property
|
|
173
|
+
def po_errors(self) -> list[Error]:
|
|
174
|
+
return [err for po_res in self.po_results for err in po_res.errors]
|
|
175
|
+
|
|
176
|
+
@property
|
|
177
|
+
def all_errors(self) -> list[Error]:
|
|
178
|
+
"""
|
|
179
|
+
Non-proof-obligation errors and proof-obligation errors.
|
|
180
|
+
|
|
181
|
+
Non-proof-obligation errors always come first
|
|
182
|
+
"""
|
|
183
|
+
return self.errors + self.po_errors
|
|
184
|
+
|
|
185
|
+
@property
|
|
186
|
+
def has_errors(self) -> bool:
|
|
187
|
+
return len(self.all_errors) > 0
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
class VerifySrcReq(BaseModel):
|
|
191
|
+
session: Session | None = Field(default=None)
|
|
192
|
+
src: str = Field(description='source code')
|
|
193
|
+
hints: str | None = Field(default=None)
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
class VerifyNameReq(BaseModel):
|
|
197
|
+
session: Session | None = Field(default=None)
|
|
198
|
+
name: str = Field(description='name of the predicate to verify')
|
|
199
|
+
hints: str | None = Field(default=None)
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
class InstanceSrcReq(BaseModel):
|
|
203
|
+
session: Session | None = Field(default=None)
|
|
204
|
+
src: str = Field(description='source code')
|
|
205
|
+
hints: str | None = Field(default=None)
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
class InstanceNameReq(BaseModel):
|
|
209
|
+
session: Session | None = Field(default=None)
|
|
210
|
+
name: str = Field(description='name of the predicate to verify')
|
|
211
|
+
hints: str | None = Field(default=None)
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
class Proved(BaseModel):
|
|
215
|
+
proof_pp: str | None = Field(default=None)
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
class Verified_upto(BaseModel):
|
|
219
|
+
msg: str | None = Field(default=None)
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
class Unsat(BaseModel):
|
|
223
|
+
proof_pp: str | None = Field(default=None)
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
class ModelType(Enum):
|
|
227
|
+
Counter_example = 'Counter_example'
|
|
228
|
+
Instance = 'Instance'
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
class Model(BaseModel):
|
|
232
|
+
m_type: ModelType # NOTE: proto file has this but it's not returned?
|
|
233
|
+
src: str = Field(description='iml source code for the model')
|
|
234
|
+
artifact: Art | None = Field(default=None, description='the model as an artifact')
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
class Refuted(BaseModel):
|
|
238
|
+
model: Model | None = Field(default=None)
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
class Sat(BaseModel):
|
|
242
|
+
model: Model | None = Field(default=None)
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
class CounterSat(BaseModel):
|
|
246
|
+
model: Model | None = Field(default=None)
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
class PO_Res(BaseModel):
|
|
250
|
+
unknown: StringMsg | None = Field(default=None)
|
|
251
|
+
err: Empty | None = Field(default=None)
|
|
252
|
+
proof: Proved | None = Field(default=None)
|
|
253
|
+
instance: CounterSat | None = Field(default=None)
|
|
254
|
+
verified_upto: Verified_upto | None = Field(default=None)
|
|
255
|
+
|
|
256
|
+
errors: list[Error] = Field(default_factory=lambda: [])
|
|
257
|
+
task: Task | None = Field(default=None, description='the ID of the task')
|
|
258
|
+
origin: Origin | None = Field(
|
|
259
|
+
default=None, description='where did the task originate?'
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
@model_validator(mode='after')
|
|
263
|
+
def one_of_res(self) -> Self:
|
|
264
|
+
sum_of_res = sum(
|
|
265
|
+
1
|
|
266
|
+
for r in [
|
|
267
|
+
self.unknown,
|
|
268
|
+
self.err,
|
|
269
|
+
self.proof,
|
|
270
|
+
self.instance,
|
|
271
|
+
self.verified_upto,
|
|
272
|
+
]
|
|
273
|
+
if r is not None
|
|
274
|
+
)
|
|
275
|
+
if sum_of_res != 1:
|
|
276
|
+
raise ValueError(
|
|
277
|
+
'Exactly one of unknown, err, proof, instance, verified_upto must be '
|
|
278
|
+
'set'
|
|
279
|
+
)
|
|
280
|
+
return self
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
class VerifyRes(BaseModel):
|
|
284
|
+
unknown: StringMsg | None = Field(default=None)
|
|
285
|
+
err: Empty | None = Field(default=None)
|
|
286
|
+
proved: Proved | None = Field(default=None)
|
|
287
|
+
refuted: Refuted | None = Field(default=None)
|
|
288
|
+
verified_upto: Verified_upto | None = Field(default=None)
|
|
289
|
+
|
|
290
|
+
errors: list[Error] = Field(default_factory=lambda: [])
|
|
291
|
+
task: Task | None = Field(default=None, description='the ID of the task')
|
|
292
|
+
|
|
293
|
+
@property
|
|
294
|
+
def res_type(
|
|
295
|
+
self,
|
|
296
|
+
) -> Literal['unknown', 'err', 'proved', 'refuted', 'verified_upto']:
|
|
297
|
+
if self.unknown is not None:
|
|
298
|
+
return 'unknown'
|
|
299
|
+
elif self.err is not None:
|
|
300
|
+
return 'err'
|
|
301
|
+
elif self.proved is not None:
|
|
302
|
+
return 'proved'
|
|
303
|
+
elif self.refuted is not None:
|
|
304
|
+
return 'refuted'
|
|
305
|
+
elif self.verified_upto is not None:
|
|
306
|
+
return 'verified_upto'
|
|
307
|
+
else:
|
|
308
|
+
raise AssertionError('Never')
|
|
309
|
+
|
|
310
|
+
@property
|
|
311
|
+
def res(self) -> StringMsg | Empty | Proved | Refuted | Verified_upto:
|
|
312
|
+
if self.unknown is not None:
|
|
313
|
+
return self.unknown
|
|
314
|
+
elif self.err is not None:
|
|
315
|
+
return self.err
|
|
316
|
+
elif self.proved is not None:
|
|
317
|
+
return self.proved
|
|
318
|
+
elif self.refuted is not None:
|
|
319
|
+
return self.refuted
|
|
320
|
+
elif self.verified_upto is not None:
|
|
321
|
+
return self.verified_upto
|
|
322
|
+
else:
|
|
323
|
+
raise AssertionError('Never')
|
|
324
|
+
|
|
325
|
+
@model_validator(mode='after')
|
|
326
|
+
def one_of_res(self) -> Self:
|
|
327
|
+
sum_of_res = sum(
|
|
328
|
+
1
|
|
329
|
+
for r in [
|
|
330
|
+
self.unknown,
|
|
331
|
+
self.err,
|
|
332
|
+
self.proved,
|
|
333
|
+
self.refuted,
|
|
334
|
+
self.verified_upto,
|
|
335
|
+
]
|
|
336
|
+
if r is not None
|
|
337
|
+
)
|
|
338
|
+
if sum_of_res != 1:
|
|
339
|
+
raise ValueError(
|
|
340
|
+
'Exactly one of unknown, err, proved, refuted, verified_upto must be '
|
|
341
|
+
'set'
|
|
342
|
+
)
|
|
343
|
+
return self
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
class InstanceRes(BaseModel):
|
|
347
|
+
unknown: StringMsg | None = Field(default=None)
|
|
348
|
+
err: Empty | None = Field(default=None)
|
|
349
|
+
unsat: Unsat | None = Field(default=None)
|
|
350
|
+
sat: Sat | None = Field(default=None)
|
|
351
|
+
|
|
352
|
+
errors: list[Error] = Field(default_factory=lambda: [])
|
|
353
|
+
task: Task | None = Field(default=None, description='the ID of the task')
|
|
354
|
+
|
|
355
|
+
@model_validator(mode='after')
|
|
356
|
+
def one_of_res(self) -> Self:
|
|
357
|
+
sum_of_res = sum(
|
|
358
|
+
1 for r in [self.unknown, self.err, self.unsat, self.sat] if r is not None
|
|
359
|
+
)
|
|
360
|
+
if sum_of_res != 1:
|
|
361
|
+
raise ValueError('Exactly one of unknown, err, unsat, sat must be set')
|
|
362
|
+
return self
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
class TypecheckReq(BaseModel):
|
|
366
|
+
session: Session | None = Field(default=None)
|
|
367
|
+
src: str = Field(description='source code to evaluate')
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
class TypecheckResProto(BaseModel):
|
|
371
|
+
success: bool
|
|
372
|
+
types: str = Field(description='JSON string of inferred types')
|
|
373
|
+
errors: list[Error] = Field(default_factory=lambda: [])
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
class InferredType(BaseModel):
|
|
377
|
+
name: str
|
|
378
|
+
ty: str = Field(description='inferred type')
|
|
379
|
+
line: int = Field(description='line number')
|
|
380
|
+
column: int = Field(description='column number')
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
InferredTypes = TypeAdapter(list[InferredType])
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
class TypecheckRes(TypecheckResProto):
|
|
387
|
+
types: list[InferredType] = Field(description='Parsed inferred types') # type: ignore[assignment]
|
|
388
|
+
|
|
389
|
+
@field_validator('types', mode='before')
|
|
390
|
+
@classmethod
|
|
391
|
+
def validate_types(cls, v: str | list[InferredType]) -> list[InferredType]:
|
|
392
|
+
if isinstance(v, str):
|
|
393
|
+
# Parse JSON string into list of dicts and validate with pydantic
|
|
394
|
+
types_list = InferredTypes.validate_json(v)
|
|
395
|
+
return types_list
|
|
396
|
+
return v
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
class OneshotReq(BaseModel):
|
|
400
|
+
input: str = Field(description='some iml code')
|
|
401
|
+
timeout: float | None = Field(default=None)
|
|
402
|
+
|
|
403
|
+
|
|
404
|
+
class OneshotRes(BaseModel):
|
|
405
|
+
class Stats(BaseModel):
|
|
406
|
+
time: float
|
|
407
|
+
|
|
408
|
+
results: list[str] = Field(default_factory=list)
|
|
409
|
+
errors: list[str] = Field(default_factory=list)
|
|
410
|
+
stats: Stats | None = Field(default=None)
|
|
411
|
+
detailed_results: list[str] = Field(default_factory=list)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from enum import Enum
|
|
4
|
+
|
|
5
|
+
from pydantic import Field
|
|
6
|
+
|
|
7
|
+
from ..proto_utils import BaseModel
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class TaskKind(Enum):
|
|
11
|
+
TASK_UNSPECIFIED = 'TASK_UNSPECIFIED'
|
|
12
|
+
TASK_EVAL = 'TASK_EVAL'
|
|
13
|
+
TASK_CHECK_PO = 'TASK_CHECK_PO'
|
|
14
|
+
TASK_PROOF_CHECK = 'TASK_PROOF_CHECK'
|
|
15
|
+
TASK_DECOMP = 'TASK_DECOMP'
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class TaskID(BaseModel):
|
|
19
|
+
id: str = Field(description='The task identifier')
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class Task(BaseModel):
|
|
23
|
+
id: TaskID | None = Field(default=None)
|
|
24
|
+
kind: TaskKind
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class Origin(BaseModel):
|
|
28
|
+
from_sym: str = Field(description='Symbol from which the task originated')
|
|
29
|
+
count: int = Field(description='A counter for tasks for this symbol')
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
from google.protobuf.json_format import MessageToDict
|
|
4
|
+
from google.protobuf.message import Message
|
|
5
|
+
from pydantic import BaseModel as PydanticBaseModel, model_validator
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def proto_to_dict(proto_obj: Message) -> dict[Any, Any]:
|
|
9
|
+
return MessageToDict(
|
|
10
|
+
proto_obj,
|
|
11
|
+
preserving_proto_field_name=True,
|
|
12
|
+
always_print_fields_with_no_presence=True,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class BaseModel(PydanticBaseModel):
|
|
17
|
+
@model_validator(mode='before')
|
|
18
|
+
def validate_proto(cls, v: Any) -> dict[Any, Any]:
|
|
19
|
+
if isinstance(v, Message):
|
|
20
|
+
return proto_to_dict(v)
|
|
21
|
+
return v
|
|
File without changes
|