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
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
"""Shared contract predicates for Serenecode.
|
|
2
|
+
|
|
3
|
+
This module contains reusable boolean predicate functions used in
|
|
4
|
+
icontract decorators across the codebase. All predicates are pure
|
|
5
|
+
functions with no side effects and no I/O operations.
|
|
6
|
+
|
|
7
|
+
This is a core module — no I/O imports are permitted.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import re
|
|
13
|
+
|
|
14
|
+
import icontract
|
|
15
|
+
|
|
16
|
+
# Pattern for valid snake_case identifiers
|
|
17
|
+
_SNAKE_CASE_PATTERN = re.compile(r"^[a-z][a-z0-9]*(?:_[a-z0-9]+)*$")
|
|
18
|
+
|
|
19
|
+
# Pattern for valid PascalCase identifiers
|
|
20
|
+
_PASCAL_CASE_PATTERN = re.compile(r"^[A-Z][a-zA-Z0-9]*$")
|
|
21
|
+
|
|
22
|
+
# Pattern for UPPER_SNAKE_CASE constants
|
|
23
|
+
_UPPER_SNAKE_CASE_PATTERN = re.compile(r"^[A-Z][A-Z0-9]*(?:_[A-Z0-9]+)*$")
|
|
24
|
+
|
|
25
|
+
# Valid verification levels
|
|
26
|
+
_MIN_VERIFICATION_LEVEL = 1
|
|
27
|
+
_MAX_VERIFICATION_LEVEL = 6
|
|
28
|
+
|
|
29
|
+
# Valid exit codes per spec
|
|
30
|
+
_VALID_EXIT_CODES = frozenset({0, 1, 2, 3, 4, 5, 6, 10})
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@icontract.require(lambda value: isinstance(value, str), "value must be a string")
|
|
34
|
+
@icontract.ensure(lambda result: isinstance(result, bool), "result must be a boolean")
|
|
35
|
+
def is_non_empty_string(value: str) -> bool:
|
|
36
|
+
"""Check that a string is non-empty and not just whitespace.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
value: The string to check.
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
True if the string is non-empty and contains non-whitespace characters.
|
|
43
|
+
"""
|
|
44
|
+
return len(value.strip()) > 0
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@icontract.require(lambda level: isinstance(level, int), "level must be an integer")
|
|
48
|
+
@icontract.ensure(lambda result: isinstance(result, bool), "result must be a boolean")
|
|
49
|
+
def is_valid_verification_level(level: int) -> bool:
|
|
50
|
+
"""Check that an integer is a valid verification level (1-6).
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
level: The level to validate.
|
|
54
|
+
|
|
55
|
+
Returns:
|
|
56
|
+
True if level is between 1 and 6 inclusive.
|
|
57
|
+
"""
|
|
58
|
+
return _MIN_VERIFICATION_LEVEL <= level <= _MAX_VERIFICATION_LEVEL
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
@icontract.require(lambda code: isinstance(code, int), "code must be an integer")
|
|
62
|
+
@icontract.ensure(lambda result: isinstance(result, bool), "result must be a boolean")
|
|
63
|
+
def is_valid_exit_code(code: int) -> bool:
|
|
64
|
+
"""Check that an integer is a valid Serenecode exit code.
|
|
65
|
+
|
|
66
|
+
Valid exit codes: 0 (passed), 1-5 (level failures), 10 (internal error).
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
code: The exit code to validate.
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
True if the code is a valid Serenecode exit code.
|
|
73
|
+
"""
|
|
74
|
+
# Keep this predicate solver-friendly for symbolic tools.
|
|
75
|
+
return 0 <= code <= 6 or code == 10
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
@icontract.require(lambda value: isinstance(value, int), "value must be an integer")
|
|
79
|
+
@icontract.ensure(lambda result: isinstance(result, bool), "result must be a boolean")
|
|
80
|
+
def is_non_negative_int(value: int) -> bool:
|
|
81
|
+
"""Check that an integer is non-negative.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
value: The integer to check.
|
|
85
|
+
|
|
86
|
+
Returns:
|
|
87
|
+
True if value is an integer >= 0.
|
|
88
|
+
"""
|
|
89
|
+
return value >= 0
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
@icontract.require(lambda value: isinstance(value, int), "value must be an integer")
|
|
93
|
+
@icontract.ensure(lambda result: isinstance(result, bool), "result must be a boolean")
|
|
94
|
+
def is_positive_int(value: int) -> bool:
|
|
95
|
+
"""Check that an integer is positive (>= 1).
|
|
96
|
+
|
|
97
|
+
Args:
|
|
98
|
+
value: The integer to check.
|
|
99
|
+
|
|
100
|
+
Returns:
|
|
101
|
+
True if value is an integer >= 1.
|
|
102
|
+
"""
|
|
103
|
+
return value >= 1
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
@icontract.require(lambda value: isinstance(value, str), "value must be a string")
|
|
107
|
+
@icontract.ensure(lambda result: isinstance(result, bool), "result must be a boolean")
|
|
108
|
+
def is_valid_file_path_string(value: str) -> bool:
|
|
109
|
+
"""Check that a string looks like a valid file path syntactically.
|
|
110
|
+
|
|
111
|
+
This is a pure syntactic check — it does not touch the filesystem.
|
|
112
|
+
Checks that the string is non-empty and does not contain null bytes.
|
|
113
|
+
|
|
114
|
+
Args:
|
|
115
|
+
value: The string to check.
|
|
116
|
+
|
|
117
|
+
Returns:
|
|
118
|
+
True if value is a syntactically valid file path string.
|
|
119
|
+
"""
|
|
120
|
+
return len(value) > 0 and "\x00" not in value
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
@icontract.require(lambda name: isinstance(name, str), "name must be a string")
|
|
124
|
+
@icontract.ensure(lambda result: isinstance(result, bool), "result must be a boolean")
|
|
125
|
+
def is_snake_case(name: str) -> bool:
|
|
126
|
+
"""Check that a name follows snake_case convention.
|
|
127
|
+
|
|
128
|
+
Args:
|
|
129
|
+
name: The identifier to check.
|
|
130
|
+
|
|
131
|
+
Returns:
|
|
132
|
+
True if the name is valid snake_case.
|
|
133
|
+
"""
|
|
134
|
+
return bool(_SNAKE_CASE_PATTERN.match(name))
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
@icontract.require(lambda name: isinstance(name, str), "name must be a string")
|
|
138
|
+
@icontract.ensure(lambda result: isinstance(result, bool), "result must be a boolean")
|
|
139
|
+
def is_pascal_case(name: str) -> bool:
|
|
140
|
+
"""Check that a name follows PascalCase convention.
|
|
141
|
+
|
|
142
|
+
Args:
|
|
143
|
+
name: The identifier to check.
|
|
144
|
+
|
|
145
|
+
Returns:
|
|
146
|
+
True if the name is valid PascalCase.
|
|
147
|
+
"""
|
|
148
|
+
return bool(_PASCAL_CASE_PATTERN.match(name))
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
@icontract.require(lambda name: isinstance(name, str), "name must be a string")
|
|
152
|
+
@icontract.ensure(lambda result: isinstance(result, bool), "result must be a boolean")
|
|
153
|
+
def is_upper_snake_case(name: str) -> bool:
|
|
154
|
+
"""Check that a name follows UPPER_SNAKE_CASE convention.
|
|
155
|
+
|
|
156
|
+
Args:
|
|
157
|
+
name: The identifier to check.
|
|
158
|
+
|
|
159
|
+
Returns:
|
|
160
|
+
True if the name is valid UPPER_SNAKE_CASE.
|
|
161
|
+
"""
|
|
162
|
+
return bool(_UPPER_SNAKE_CASE_PATTERN.match(name))
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
@icontract.require(lambda name: isinstance(name, str), "name must be a string")
|
|
166
|
+
@icontract.ensure(lambda result: isinstance(result, bool), "result must be a boolean")
|
|
167
|
+
def is_valid_template_name(name: str) -> bool:
|
|
168
|
+
"""Check that a template name is one of the recognized templates.
|
|
169
|
+
|
|
170
|
+
Args:
|
|
171
|
+
name: The template name to check.
|
|
172
|
+
|
|
173
|
+
Returns:
|
|
174
|
+
True if name is 'default', 'strict', or 'minimal'.
|
|
175
|
+
"""
|
|
176
|
+
return name in ("default", "strict", "minimal")
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""Domain exception hierarchy for Serenecode.
|
|
2
|
+
|
|
3
|
+
This module defines all domain-specific exceptions used throughout
|
|
4
|
+
the Serenecode codebase. All exceptions inherit from SerenecodeError,
|
|
5
|
+
which is the base exception for the entire framework.
|
|
6
|
+
|
|
7
|
+
This is a core module — no I/O imports are permitted.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class SerenecodeError(Exception):
|
|
14
|
+
"""Base exception for all Serenecode errors."""
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class ConfigurationError(SerenecodeError):
|
|
18
|
+
"""Raised when SERENECODE.md parsing or configuration fails."""
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class StructuralViolationError(SerenecodeError):
|
|
22
|
+
"""Raised when code does not follow SERENECODE.md structural conventions."""
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class VerificationError(SerenecodeError):
|
|
26
|
+
"""Raised when formal verification finds a counterexample."""
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class InitializationError(SerenecodeError):
|
|
30
|
+
"""Raised when project initialization fails."""
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class ToolNotInstalledError(SerenecodeError):
|
|
34
|
+
"""Raised when a required external tool is not installed."""
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class UnsafeCodeExecutionError(SerenecodeError):
|
|
38
|
+
"""Raised when deep verification is requested without trusting the code."""
|