serenecode 0.1.0__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.
- serenecode/__init__.py +281 -0
- serenecode/adapters/__init__.py +6 -0
- serenecode/adapters/coverage_adapter.py +1173 -0
- serenecode/adapters/crosshair_adapter.py +1069 -0
- serenecode/adapters/hypothesis_adapter.py +1824 -0
- serenecode/adapters/local_fs.py +169 -0
- serenecode/adapters/module_loader.py +492 -0
- serenecode/adapters/mypy_adapter.py +161 -0
- serenecode/checker/__init__.py +6 -0
- serenecode/checker/compositional.py +2216 -0
- serenecode/checker/coverage.py +186 -0
- serenecode/checker/properties.py +154 -0
- serenecode/checker/structural.py +1504 -0
- serenecode/checker/symbolic.py +178 -0
- serenecode/checker/types.py +148 -0
- serenecode/cli.py +478 -0
- serenecode/config.py +711 -0
- serenecode/contracts/__init__.py +6 -0
- serenecode/contracts/predicates.py +176 -0
- serenecode/core/__init__.py +6 -0
- serenecode/core/exceptions.py +38 -0
- serenecode/core/pipeline.py +807 -0
- serenecode/init.py +307 -0
- serenecode/models.py +308 -0
- serenecode/ports/__init__.py +6 -0
- serenecode/ports/coverage_analyzer.py +124 -0
- serenecode/ports/file_system.py +95 -0
- serenecode/ports/property_tester.py +69 -0
- serenecode/ports/symbolic_checker.py +70 -0
- serenecode/ports/type_checker.py +66 -0
- serenecode/reporter.py +346 -0
- serenecode/source_discovery.py +319 -0
- serenecode/templates/__init__.py +5 -0
- serenecode/templates/content.py +337 -0
- serenecode-0.1.0.dist-info/METADATA +298 -0
- serenecode-0.1.0.dist-info/RECORD +39 -0
- serenecode-0.1.0.dist-info/WHEEL +4 -0
- serenecode-0.1.0.dist-info/entry_points.txt +2 -0
- serenecode-0.1.0.dist-info/licenses/LICENSE +21 -0
serenecode/__init__.py
ADDED
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
"""Serenecode — formal verification framework for AI-generated Python code.
|
|
2
|
+
|
|
3
|
+
This module provides the public API surface for Serenecode. It enables
|
|
4
|
+
programmatic access to project initialization and all verification levels.
|
|
5
|
+
This is a composition root — it wires adapters to ports and delegates
|
|
6
|
+
to core logic via the pipeline.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import icontract
|
|
12
|
+
|
|
13
|
+
from serenecode.adapters.local_fs import LocalFileReader, LocalFileWriter
|
|
14
|
+
from serenecode.config import default_config, parse_serenecode_md
|
|
15
|
+
from serenecode.contracts.predicates import (
|
|
16
|
+
is_non_empty_string,
|
|
17
|
+
is_valid_file_path_string,
|
|
18
|
+
is_valid_template_name,
|
|
19
|
+
is_valid_verification_level,
|
|
20
|
+
)
|
|
21
|
+
from serenecode.core.exceptions import UnsafeCodeExecutionError
|
|
22
|
+
from serenecode.core.pipeline import run_pipeline
|
|
23
|
+
from serenecode.init import InitResult, initialize_project
|
|
24
|
+
from serenecode.models import CheckResult
|
|
25
|
+
from serenecode.source_discovery import build_source_files, find_serenecode_md
|
|
26
|
+
|
|
27
|
+
_TRUST_REQUIRED_MESSAGE = (
|
|
28
|
+
"Levels 3-6 import and execute project modules. "
|
|
29
|
+
"Pass allow_code_execution=True only for trusted code."
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@icontract.require(lambda path: is_non_empty_string(path), "path must be a non-empty string")
|
|
34
|
+
@icontract.require(lambda path: is_valid_file_path_string(path), "path must be a valid path string")
|
|
35
|
+
@icontract.require(lambda template: is_valid_template_name(template), "template must be a valid template name")
|
|
36
|
+
@icontract.ensure(lambda result: isinstance(result, InitResult), "result must be an InitResult")
|
|
37
|
+
def init(path: str = ".", template: str = "default") -> InitResult:
|
|
38
|
+
"""Initialize a Serenecode project.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
path: Project root directory.
|
|
42
|
+
template: Template name ('default', 'strict', or 'minimal').
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
An InitResult describing what was created.
|
|
46
|
+
"""
|
|
47
|
+
reader = LocalFileReader()
|
|
48
|
+
writer = LocalFileWriter()
|
|
49
|
+
return initialize_project(
|
|
50
|
+
directory=path,
|
|
51
|
+
template=template,
|
|
52
|
+
file_reader=reader,
|
|
53
|
+
file_writer=writer,
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
@icontract.require(lambda path: is_non_empty_string(path), "path must be a non-empty string")
|
|
58
|
+
@icontract.require(lambda path: is_valid_file_path_string(path), "path must be a valid path string")
|
|
59
|
+
@icontract.require(lambda level: is_valid_verification_level(level), "level must be between 1 and 6")
|
|
60
|
+
@icontract.ensure(lambda result: isinstance(result, CheckResult), "result must be a CheckResult")
|
|
61
|
+
def check(
|
|
62
|
+
path: str = ".",
|
|
63
|
+
level: int = 6,
|
|
64
|
+
allow_code_execution: bool = False,
|
|
65
|
+
) -> CheckResult:
|
|
66
|
+
"""Run verification up to the specified level.
|
|
67
|
+
|
|
68
|
+
Uses the full pipeline (L1 through the requested level),
|
|
69
|
+
wiring adapters for each level that has a backend available.
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
path: File or directory to check.
|
|
73
|
+
level: Maximum verification level (1-6).
|
|
74
|
+
allow_code_execution: Explicit opt-in for Levels 3-6, which import
|
|
75
|
+
and execute project modules.
|
|
76
|
+
|
|
77
|
+
Returns:
|
|
78
|
+
A CheckResult with all findings.
|
|
79
|
+
"""
|
|
80
|
+
return _run_check(path, level, allow_code_execution=allow_code_execution)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
@icontract.require(lambda path: is_non_empty_string(path), "path must be a non-empty string")
|
|
84
|
+
@icontract.require(lambda path: is_valid_file_path_string(path), "path must be a valid path string")
|
|
85
|
+
@icontract.ensure(lambda result: isinstance(result, CheckResult), "result must be a CheckResult")
|
|
86
|
+
def check_structural(path: str = ".") -> CheckResult:
|
|
87
|
+
"""Run only the structural checker (Level 1).
|
|
88
|
+
|
|
89
|
+
Args:
|
|
90
|
+
path: File or directory to check.
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
A CheckResult with structural findings only.
|
|
94
|
+
"""
|
|
95
|
+
return _run_check(path, level=1)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
@icontract.require(lambda path: is_non_empty_string(path), "path must be a non-empty string")
|
|
99
|
+
@icontract.require(lambda path: is_valid_file_path_string(path), "path must be a valid path string")
|
|
100
|
+
@icontract.ensure(lambda result: isinstance(result, CheckResult), "result must be a CheckResult")
|
|
101
|
+
def check_types(path: str = ".") -> CheckResult:
|
|
102
|
+
"""Run the Level 2 type checker."""
|
|
103
|
+
return _run_check(path, level=2)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
@icontract.require(lambda path: is_non_empty_string(path), "path must be a non-empty string")
|
|
107
|
+
@icontract.require(lambda path: is_valid_file_path_string(path), "path must be a valid path string")
|
|
108
|
+
@icontract.ensure(lambda result: isinstance(result, CheckResult), "result must be a CheckResult")
|
|
109
|
+
def check_coverage(
|
|
110
|
+
path: str = ".",
|
|
111
|
+
allow_code_execution: bool = False,
|
|
112
|
+
) -> CheckResult:
|
|
113
|
+
"""Run verification through Level 3 (coverage analysis).
|
|
114
|
+
|
|
115
|
+
Args:
|
|
116
|
+
path: File or directory to check.
|
|
117
|
+
allow_code_execution: Explicit opt-in because Levels 3-6 import and
|
|
118
|
+
execute project modules.
|
|
119
|
+
|
|
120
|
+
Returns:
|
|
121
|
+
CheckResult through Level 3.
|
|
122
|
+
"""
|
|
123
|
+
return _run_check(path, level=3, allow_code_execution=allow_code_execution)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
@icontract.require(lambda path: is_non_empty_string(path), "path must be a non-empty string")
|
|
127
|
+
@icontract.require(lambda path: is_valid_file_path_string(path), "path must be a valid path string")
|
|
128
|
+
@icontract.ensure(lambda result: isinstance(result, CheckResult), "result must be a CheckResult")
|
|
129
|
+
def check_properties(
|
|
130
|
+
path: str = ".",
|
|
131
|
+
allow_code_execution: bool = False,
|
|
132
|
+
) -> CheckResult:
|
|
133
|
+
"""Run property-based verification through Level 4.
|
|
134
|
+
|
|
135
|
+
Args:
|
|
136
|
+
path: File or directory to check.
|
|
137
|
+
allow_code_execution: Explicit opt-in because Level 4 imports and
|
|
138
|
+
executes project modules.
|
|
139
|
+
|
|
140
|
+
Returns:
|
|
141
|
+
A CheckResult with findings through Level 4.
|
|
142
|
+
"""
|
|
143
|
+
return _run_check(path, level=4, allow_code_execution=allow_code_execution)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
@icontract.require(lambda path: is_non_empty_string(path), "path must be a non-empty string")
|
|
147
|
+
@icontract.require(lambda path: is_valid_file_path_string(path), "path must be a valid path string")
|
|
148
|
+
@icontract.ensure(lambda result: isinstance(result, CheckResult), "result must be a CheckResult")
|
|
149
|
+
def check_symbolic(
|
|
150
|
+
path: str = ".",
|
|
151
|
+
allow_code_execution: bool = False,
|
|
152
|
+
) -> CheckResult:
|
|
153
|
+
"""Run symbolic verification through Level 5.
|
|
154
|
+
|
|
155
|
+
Args:
|
|
156
|
+
path: File or directory to check.
|
|
157
|
+
allow_code_execution: Explicit opt-in because Levels 3-6 import and
|
|
158
|
+
execute project modules.
|
|
159
|
+
|
|
160
|
+
Returns:
|
|
161
|
+
A CheckResult with findings through Level 5.
|
|
162
|
+
"""
|
|
163
|
+
return _run_check(path, level=5, allow_code_execution=allow_code_execution)
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
@icontract.require(lambda path: is_non_empty_string(path), "path must be a non-empty string")
|
|
167
|
+
@icontract.require(lambda path: is_valid_file_path_string(path), "path must be a valid path string")
|
|
168
|
+
@icontract.ensure(lambda result: isinstance(result, CheckResult), "result must be a CheckResult")
|
|
169
|
+
def check_compositional(
|
|
170
|
+
path: str = ".",
|
|
171
|
+
allow_code_execution: bool = False,
|
|
172
|
+
) -> CheckResult:
|
|
173
|
+
"""Run compositional verification through Level 6.
|
|
174
|
+
|
|
175
|
+
Args:
|
|
176
|
+
path: File or directory to check.
|
|
177
|
+
allow_code_execution: Explicit opt-in because Levels 3-6 import and
|
|
178
|
+
execute project modules during the full pipeline.
|
|
179
|
+
|
|
180
|
+
Returns:
|
|
181
|
+
A CheckResult with findings through Level 6.
|
|
182
|
+
"""
|
|
183
|
+
return _run_check(path, level=6, allow_code_execution=allow_code_execution)
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
@icontract.require(lambda path: is_non_empty_string(path), "path must be a non-empty string")
|
|
187
|
+
@icontract.require(lambda path: is_valid_file_path_string(path), "path must be a valid path string")
|
|
188
|
+
@icontract.ensure(lambda result: isinstance(result, CheckResult), "result must be a CheckResult")
|
|
189
|
+
def status(path: str = ".") -> CheckResult:
|
|
190
|
+
"""Show verification status of the codebase.
|
|
191
|
+
|
|
192
|
+
Args:
|
|
193
|
+
path: File or directory to check.
|
|
194
|
+
|
|
195
|
+
Returns:
|
|
196
|
+
A CheckResult showing current verification state.
|
|
197
|
+
"""
|
|
198
|
+
return _run_check(path, level=1)
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
@icontract.require(lambda path: is_non_empty_string(path), "path must be a non-empty string")
|
|
202
|
+
@icontract.require(lambda path: is_valid_file_path_string(path), "path must be a valid path string")
|
|
203
|
+
@icontract.require(lambda level: is_valid_verification_level(level), "level must be between 1 and 6")
|
|
204
|
+
@icontract.ensure(lambda result: isinstance(result, CheckResult), "result must be a CheckResult")
|
|
205
|
+
def _run_check(
|
|
206
|
+
path: str,
|
|
207
|
+
level: int,
|
|
208
|
+
allow_code_execution: bool = False,
|
|
209
|
+
) -> CheckResult:
|
|
210
|
+
"""Internal helper to run checks via the real pipeline.
|
|
211
|
+
|
|
212
|
+
Args:
|
|
213
|
+
path: File or directory to check.
|
|
214
|
+
level: Maximum verification level (1-6).
|
|
215
|
+
allow_code_execution: Explicit opt-in for Levels 3-6, which import
|
|
216
|
+
and execute project modules.
|
|
217
|
+
|
|
218
|
+
Returns:
|
|
219
|
+
Aggregated CheckResult.
|
|
220
|
+
"""
|
|
221
|
+
if level >= 3 and not allow_code_execution:
|
|
222
|
+
raise UnsafeCodeExecutionError(_TRUST_REQUIRED_MESSAGE)
|
|
223
|
+
|
|
224
|
+
reader = LocalFileReader()
|
|
225
|
+
|
|
226
|
+
# Load config
|
|
227
|
+
serenecode_path = find_serenecode_md(path, reader)
|
|
228
|
+
if serenecode_path:
|
|
229
|
+
config_content = reader.read_file(serenecode_path)
|
|
230
|
+
config = parse_serenecode_md(config_content)
|
|
231
|
+
else:
|
|
232
|
+
config = default_config()
|
|
233
|
+
|
|
234
|
+
# List and build source files
|
|
235
|
+
files = reader.list_python_files(path)
|
|
236
|
+
source_files = build_source_files(files, reader, path)
|
|
237
|
+
|
|
238
|
+
# Wire up adapters for higher levels
|
|
239
|
+
type_checker = None
|
|
240
|
+
coverage_analyzer = None
|
|
241
|
+
property_tester = None
|
|
242
|
+
symbolic_checker = None
|
|
243
|
+
|
|
244
|
+
if level >= 2:
|
|
245
|
+
try:
|
|
246
|
+
from serenecode.adapters.mypy_adapter import MypyTypeChecker
|
|
247
|
+
type_checker = MypyTypeChecker()
|
|
248
|
+
except ImportError:
|
|
249
|
+
pass
|
|
250
|
+
|
|
251
|
+
if level >= 3:
|
|
252
|
+
try:
|
|
253
|
+
from serenecode.adapters.coverage_adapter import CoverageAnalyzerAdapter
|
|
254
|
+
coverage_analyzer = CoverageAnalyzerAdapter(allow_code_execution=True)
|
|
255
|
+
except ImportError:
|
|
256
|
+
pass
|
|
257
|
+
|
|
258
|
+
if level >= 4:
|
|
259
|
+
try:
|
|
260
|
+
from serenecode.adapters.hypothesis_adapter import HypothesisPropertyTester
|
|
261
|
+
property_tester = HypothesisPropertyTester(allow_code_execution=True)
|
|
262
|
+
except ImportError:
|
|
263
|
+
pass
|
|
264
|
+
|
|
265
|
+
if level >= 5:
|
|
266
|
+
try:
|
|
267
|
+
from serenecode.adapters.crosshair_adapter import CrossHairSymbolicChecker
|
|
268
|
+
symbolic_checker = CrossHairSymbolicChecker(allow_code_execution=True)
|
|
269
|
+
except ImportError:
|
|
270
|
+
pass
|
|
271
|
+
|
|
272
|
+
return run_pipeline(
|
|
273
|
+
source_files=source_files,
|
|
274
|
+
level=level,
|
|
275
|
+
start_level=1,
|
|
276
|
+
config=config,
|
|
277
|
+
type_checker=type_checker,
|
|
278
|
+
coverage_analyzer=coverage_analyzer,
|
|
279
|
+
property_tester=property_tester,
|
|
280
|
+
symbolic_checker=symbolic_checker,
|
|
281
|
+
)
|