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.
Files changed (39) hide show
  1. serenecode/__init__.py +281 -0
  2. serenecode/adapters/__init__.py +6 -0
  3. serenecode/adapters/coverage_adapter.py +1173 -0
  4. serenecode/adapters/crosshair_adapter.py +1069 -0
  5. serenecode/adapters/hypothesis_adapter.py +1824 -0
  6. serenecode/adapters/local_fs.py +169 -0
  7. serenecode/adapters/module_loader.py +492 -0
  8. serenecode/adapters/mypy_adapter.py +161 -0
  9. serenecode/checker/__init__.py +6 -0
  10. serenecode/checker/compositional.py +2216 -0
  11. serenecode/checker/coverage.py +186 -0
  12. serenecode/checker/properties.py +154 -0
  13. serenecode/checker/structural.py +1504 -0
  14. serenecode/checker/symbolic.py +178 -0
  15. serenecode/checker/types.py +148 -0
  16. serenecode/cli.py +478 -0
  17. serenecode/config.py +711 -0
  18. serenecode/contracts/__init__.py +6 -0
  19. serenecode/contracts/predicates.py +176 -0
  20. serenecode/core/__init__.py +6 -0
  21. serenecode/core/exceptions.py +38 -0
  22. serenecode/core/pipeline.py +807 -0
  23. serenecode/init.py +307 -0
  24. serenecode/models.py +308 -0
  25. serenecode/ports/__init__.py +6 -0
  26. serenecode/ports/coverage_analyzer.py +124 -0
  27. serenecode/ports/file_system.py +95 -0
  28. serenecode/ports/property_tester.py +69 -0
  29. serenecode/ports/symbolic_checker.py +70 -0
  30. serenecode/ports/type_checker.py +66 -0
  31. serenecode/reporter.py +346 -0
  32. serenecode/source_discovery.py +319 -0
  33. serenecode/templates/__init__.py +5 -0
  34. serenecode/templates/content.py +337 -0
  35. serenecode-0.1.0.dist-info/METADATA +298 -0
  36. serenecode-0.1.0.dist-info/RECORD +39 -0
  37. serenecode-0.1.0.dist-info/WHEEL +4 -0
  38. serenecode-0.1.0.dist-info/entry_points.txt +2 -0
  39. serenecode-0.1.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,6 @@
1
+ """Shared contract predicates for Serenecode.
2
+
3
+ This package contains reusable boolean predicate functions used
4
+ in icontract decorators across the codebase. All predicates are
5
+ pure functions with no side effects.
6
+ """
@@ -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,6 @@
1
+ """Core domain logic for Serenecode.
2
+
3
+ This package contains pure domain logic with no I/O operations.
4
+ All modules in this package must be free of side effects and must not
5
+ import I/O libraries such as os, pathlib, subprocess, or requests.
6
+ """
@@ -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."""