python-code-validator 0.1.1__tar.gz → 0.1.3__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.
- {python_code_validator-0.1.1/src/python_code_validator.egg-info → python_code_validator-0.1.3}/PKG-INFO +15 -9
- {python_code_validator-0.1.1 → python_code_validator-0.1.3}/README.md +3 -3
- python_code_validator-0.1.3/pyproject.toml +119 -0
- python_code_validator-0.1.3/src/code_validator/__init__.py +57 -0
- python_code_validator-0.1.3/src/code_validator/__main__.py +20 -0
- {python_code_validator-0.1.1 → python_code_validator-0.1.3}/src/code_validator/cli.py +22 -8
- {python_code_validator-0.1.1 → python_code_validator-0.1.3}/src/code_validator/components/ast_utils.py +6 -2
- {python_code_validator-0.1.1 → python_code_validator-0.1.3}/src/code_validator/components/definitions.py +6 -5
- {python_code_validator-0.1.1 → python_code_validator-0.1.3}/src/code_validator/components/factories.py +4 -3
- {python_code_validator-0.1.1 → python_code_validator-0.1.3}/src/code_validator/components/scope_handler.py +5 -3
- python_code_validator-0.1.3/src/code_validator/config.py +151 -0
- python_code_validator-0.1.3/src/code_validator/core.py +193 -0
- {python_code_validator-0.1.1 → python_code_validator-0.1.3}/src/code_validator/rules_library/basic_rules.py +16 -14
- {python_code_validator-0.1.1 → python_code_validator-0.1.3}/src/code_validator/rules_library/constraint_logic.py +36 -1
- {python_code_validator-0.1.1 → python_code_validator-0.1.3}/src/code_validator/rules_library/selector_nodes.py +57 -5
- {python_code_validator-0.1.1 → python_code_validator-0.1.3/src/python_code_validator.egg-info}/PKG-INFO +15 -9
- {python_code_validator-0.1.1 → python_code_validator-0.1.3}/src/python_code_validator.egg-info/requires.txt +2 -2
- {python_code_validator-0.1.1 → python_code_validator-0.1.3}/tests/test_validator.py +0 -1
- python_code_validator-0.1.1/pyproject.toml +0 -61
- python_code_validator-0.1.1/src/code_validator/__init__.py +0 -25
- python_code_validator-0.1.1/src/code_validator/__main__.py +0 -11
- python_code_validator-0.1.1/src/code_validator/config.py +0 -99
- python_code_validator-0.1.1/src/code_validator/core.py +0 -100
- {python_code_validator-0.1.1 → python_code_validator-0.1.3}/LICENSE +0 -0
- {python_code_validator-0.1.1 → python_code_validator-0.1.3}/setup.cfg +0 -0
- {python_code_validator-0.1.1 → python_code_validator-0.1.3}/src/code_validator/components/__init__.py +0 -0
- {python_code_validator-0.1.1 → python_code_validator-0.1.3}/src/code_validator/exceptions.py +0 -0
- {python_code_validator-0.1.1 → python_code_validator-0.1.3}/src/code_validator/output.py +0 -0
- {python_code_validator-0.1.1 → python_code_validator-0.1.3}/src/code_validator/rules_library/__init__.py +0 -0
- {python_code_validator-0.1.1 → python_code_validator-0.1.3}/src/python_code_validator.egg-info/SOURCES.txt +0 -0
- {python_code_validator-0.1.1 → python_code_validator-0.1.3}/src/python_code_validator.egg-info/dependency_links.txt +0 -0
- {python_code_validator-0.1.1 → python_code_validator-0.1.3}/src/python_code_validator.egg-info/entry_points.txt +0 -0
- {python_code_validator-0.1.1 → python_code_validator-0.1.3}/src/python_code_validator.egg-info/top_level.txt +0 -0
- {python_code_validator-0.1.1 → python_code_validator-0.1.3}/tests/test_components.py +0 -0
- {python_code_validator-0.1.1 → python_code_validator-0.1.3}/tests/test_scope_handler.py +0 -0
@@ -1,7 +1,7 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: python-code-validator
|
3
|
-
Version: 0.1.
|
4
|
-
Summary: A flexible framework for static validation of Python code
|
3
|
+
Version: 0.1.3
|
4
|
+
Summary: A flexible, AST-based framework for static validation of Python code using declarative JSON rules.
|
5
5
|
Author-email: Qu1nel <covach.qn@gmail.com>
|
6
6
|
License: MIT License
|
7
7
|
|
@@ -26,23 +26,29 @@ License: MIT License
|
|
26
26
|
SOFTWARE.
|
27
27
|
|
28
28
|
Project-URL: Homepage, https://github.com/Qu1nel/PythonCodeValidator
|
29
|
+
Project-URL: Documentation, https://pythoncodevalidator.readthedocs.io/en/latest/
|
29
30
|
Project-URL: Bug Tracker, https://github.com/Qu1nel/PythonCodeValidator/issues
|
30
|
-
Keywords: validation,linter,static analysis,testing,education
|
31
|
-
Classifier: Development Status ::
|
31
|
+
Keywords: validation,linter,static analysis,testing,education,ast
|
32
|
+
Classifier: Development Status :: 4 - Beta
|
33
|
+
Classifier: Intended Audience :: Developers
|
34
|
+
Classifier: Intended Audience :: Education
|
32
35
|
Classifier: Programming Language :: Python :: 3
|
33
36
|
Classifier: Programming Language :: Python :: 3.11
|
34
37
|
Classifier: Programming Language :: Python :: 3.12
|
35
38
|
Classifier: License :: OSI Approved :: MIT License
|
36
39
|
Classifier: Operating System :: OS Independent
|
40
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
41
|
+
Classifier: Topic :: Software Development :: Testing
|
42
|
+
Classifier: Topic :: Education
|
37
43
|
Requires-Python: >=3.11
|
38
44
|
Description-Content-Type: text/markdown
|
39
45
|
License-File: LICENSE
|
46
|
+
Requires-Dist: flake8>=7.0.0
|
40
47
|
Provides-Extra: dev
|
41
48
|
Requires-Dist: ruff>=0.4.0; extra == "dev"
|
42
|
-
Requires-Dist: flake8>=7.0.0; extra == "dev"
|
43
49
|
Requires-Dist: build; extra == "dev"
|
44
50
|
Requires-Dist: twine; extra == "dev"
|
45
|
-
Requires-Dist: coverage>=7.5.0; extra == "dev"
|
51
|
+
Requires-Dist: coverage[toml]>=7.5.0; extra == "dev"
|
46
52
|
Provides-Extra: docs
|
47
53
|
Requires-Dist: sphinx>=7.0.0; extra == "docs"
|
48
54
|
Requires-Dist: furo; extra == "docs"
|
@@ -78,9 +84,9 @@ Dynamic: license-file
|
|
78
84
|
<h4>
|
79
85
|
<a href="#-quick-usage-example">Usage Examples</a>
|
80
86
|
<span>·</span>
|
81
|
-
<a href="https://
|
87
|
+
<a href="https://pythoncodevalidator.readthedocs.io/en/latest/">Full Documentation</a>
|
82
88
|
<span>·</span>
|
83
|
-
<a href="
|
89
|
+
<a href="https://deepwiki.com/Qu1nel/PythonCodeValidator">AI documentation</a>
|
84
90
|
<span>·</span>
|
85
91
|
<a href="https://github.com/Qu1nel/PythonCodeValidator/blob/main/docs/how_it_works/index.md">Developer's Guide</a>
|
86
92
|
<span>·</span>
|
@@ -280,7 +286,7 @@ Validation failed.
|
|
280
286
|
- **Full User Guide & JSON Specification**: Our complete documentation is hosted on
|
281
287
|
**[Read the Docs](https://[your-project].readthedocs.io)**.
|
282
288
|
- **Developer's Guide**: For a deep dive into the architecture, see the
|
283
|
-
**[How It Works guide](./docs/how_it_works/index.md)**.
|
289
|
+
**[How It Works guide](./docs/how_it_works/index.md)**.
|
284
290
|
- **Interactive AI-Powered Docs**: *(Coming Soon)* An interactive documentation experience.
|
285
291
|
|
286
292
|
## 🤝 Contributing
|
@@ -26,9 +26,9 @@
|
|
26
26
|
<h4>
|
27
27
|
<a href="#-quick-usage-example">Usage Examples</a>
|
28
28
|
<span>·</span>
|
29
|
-
<a href="https://
|
29
|
+
<a href="https://pythoncodevalidator.readthedocs.io/en/latest/">Full Documentation</a>
|
30
30
|
<span>·</span>
|
31
|
-
<a href="
|
31
|
+
<a href="https://deepwiki.com/Qu1nel/PythonCodeValidator">AI documentation</a>
|
32
32
|
<span>·</span>
|
33
33
|
<a href="https://github.com/Qu1nel/PythonCodeValidator/blob/main/docs/how_it_works/index.md">Developer's Guide</a>
|
34
34
|
<span>·</span>
|
@@ -228,7 +228,7 @@ Validation failed.
|
|
228
228
|
- **Full User Guide & JSON Specification**: Our complete documentation is hosted on
|
229
229
|
**[Read the Docs](https://[your-project].readthedocs.io)**.
|
230
230
|
- **Developer's Guide**: For a deep dive into the architecture, see the
|
231
|
-
**[How It Works guide](./docs/how_it_works/index.md)**.
|
231
|
+
**[How It Works guide](./docs/how_it_works/index.md)**.
|
232
232
|
- **Interactive AI-Powered Docs**: *(Coming Soon)* An interactive documentation experience.
|
233
233
|
|
234
234
|
## 🤝 Contributing
|
@@ -0,0 +1,119 @@
|
|
1
|
+
# ==============================================================================
|
2
|
+
# Build System Configuration (PEP 517/518)
|
3
|
+
# ==============================================================================
|
4
|
+
[build-system]
|
5
|
+
requires = ["setuptools>=61.0"]
|
6
|
+
build-backend = "setuptools.build_meta"
|
7
|
+
|
8
|
+
# ==============================================================================
|
9
|
+
# Project Metadata (PEP 621)
|
10
|
+
# ==============================================================================
|
11
|
+
[project]
|
12
|
+
name = "python-code-validator"
|
13
|
+
version = "0.1.3"
|
14
|
+
authors = [{ name = "Qu1nel", email = "covach.qn@gmail.com" }]
|
15
|
+
description = "A flexible, AST-based framework for static validation of Python code using declarative JSON rules."
|
16
|
+
readme = "README.md"
|
17
|
+
requires-python = ">=3.11"
|
18
|
+
license = { file = "LICENSE" }
|
19
|
+
keywords = ["validation", "linter", "static analysis", "testing", "education", "ast"]
|
20
|
+
classifiers = [
|
21
|
+
"Development Status :: 4 - Beta",
|
22
|
+
"Intended Audience :: Developers",
|
23
|
+
"Intended Audience :: Education",
|
24
|
+
"Programming Language :: Python :: 3",
|
25
|
+
"Programming Language :: Python :: 3.11",
|
26
|
+
"Programming Language :: Python :: 3.12",
|
27
|
+
"License :: OSI Approved :: MIT License",
|
28
|
+
"Operating System :: OS Independent",
|
29
|
+
"Topic :: Software Development :: Quality Assurance",
|
30
|
+
"Topic :: Software Development :: Testing",
|
31
|
+
"Topic :: Education",
|
32
|
+
]
|
33
|
+
|
34
|
+
dependencies = [
|
35
|
+
"flake8>=7.0.0"
|
36
|
+
]
|
37
|
+
|
38
|
+
[project.urls]
|
39
|
+
"Homepage" = "https://github.com/Qu1nel/PythonCodeValidator"
|
40
|
+
"Documentation" = "https://pythoncodevalidator.readthedocs.io/en/latest/"
|
41
|
+
"Bug Tracker" = "https://github.com/Qu1nel/PythonCodeValidator/issues"
|
42
|
+
|
43
|
+
[project.scripts]
|
44
|
+
validate-code = "code_validator.cli:run_from_cli"
|
45
|
+
|
46
|
+
[project.optional-dependencies]
|
47
|
+
dev = [
|
48
|
+
"ruff>=0.4.0",
|
49
|
+
"build",
|
50
|
+
"twine",
|
51
|
+
"coverage[toml]>=7.5.0",
|
52
|
+
]
|
53
|
+
docs = [
|
54
|
+
"sphinx>=7.0.0",
|
55
|
+
"furo",
|
56
|
+
"myst-parser",
|
57
|
+
"sphinx-design",
|
58
|
+
]
|
59
|
+
|
60
|
+
# ==============================================================================
|
61
|
+
# Tool Configuration
|
62
|
+
# ==============================================================================
|
63
|
+
|
64
|
+
[tool.ruff]
|
65
|
+
line-length = 120
|
66
|
+
exclude = [
|
67
|
+
".venv",
|
68
|
+
"build",
|
69
|
+
"dist",
|
70
|
+
"src/python_code_validator.egg-info",
|
71
|
+
"tests/fixtures",
|
72
|
+
]
|
73
|
+
|
74
|
+
[tool.ruff.lint]
|
75
|
+
select = [
|
76
|
+
"E", # pycodestyle errors
|
77
|
+
"W", # pycodestyle warnings
|
78
|
+
"F", # pyflakes
|
79
|
+
"I", # isort
|
80
|
+
"B", # flake8-bugbear
|
81
|
+
"C4", # flake8-comprehensions
|
82
|
+
"D", # pydocstyle
|
83
|
+
]
|
84
|
+
ignore = [
|
85
|
+
]
|
86
|
+
|
87
|
+
[tool.ruff.lint.per-file-ignores]
|
88
|
+
"tests/*" = [
|
89
|
+
"D100", # Missing docstring in public module
|
90
|
+
"D101", # Missing docstring in public class
|
91
|
+
"D102", # Missing docstring in public method
|
92
|
+
"D103", # Missing docstring in public function
|
93
|
+
"D104", # Missing docstring in public package
|
94
|
+
"D107", # Missing docstring in __init__
|
95
|
+
]
|
96
|
+
"src/code_validator/components/__init__.py" = ["D104"]
|
97
|
+
"src/code_validator/rules_library/__init__.py" = ["D104"]
|
98
|
+
|
99
|
+
|
100
|
+
[tool.ruff.lint.pydocstyle]
|
101
|
+
convention = "google"
|
102
|
+
|
103
|
+
[tool.ruff.lint.isort]
|
104
|
+
known-first-party = ["code_validator", "tests"]
|
105
|
+
|
106
|
+
[tool.ruff.format]
|
107
|
+
quote-style = "double"
|
108
|
+
|
109
|
+
[tool.coverage.run]
|
110
|
+
omit = [
|
111
|
+
"src/code_validator/__main__.py",
|
112
|
+
"src/code_validator/cli.py",
|
113
|
+
"tests/*",
|
114
|
+
"*/__init__.py",
|
115
|
+
]
|
116
|
+
|
117
|
+
[tool.coverage.report]
|
118
|
+
fail_under = 85
|
119
|
+
show_missing = true
|
@@ -0,0 +1,57 @@
|
|
1
|
+
"""A flexible framework for static validation of Python code.
|
2
|
+
|
3
|
+
This package provides a comprehensive toolkit for statically analyzing Python
|
4
|
+
source code based on a declarative set of rules defined in a JSON format. It
|
5
|
+
allows for checking syntax, style, structure, and constraints without
|
6
|
+
executing the code.
|
7
|
+
|
8
|
+
The primary entry point for using this package programmatically is the
|
9
|
+
`StaticValidator` class.
|
10
|
+
|
11
|
+
Example:
|
12
|
+
A minimal example of using the validator as a library.
|
13
|
+
|
14
|
+
.. code-block:: python
|
15
|
+
|
16
|
+
from code_validator import StaticValidator, AppConfig, LogLevel
|
17
|
+
from code_validator.output import Console, setup_logging
|
18
|
+
from pathlib import Path
|
19
|
+
|
20
|
+
# Basic setup
|
21
|
+
logger = setup_logging(LogLevel.INFO)
|
22
|
+
console = Console(logger)
|
23
|
+
config = AppConfig(
|
24
|
+
solution_path=Path("path/to/solution.py"),
|
25
|
+
rules_path=Path("path/to/rules.json"),
|
26
|
+
log_level=LogLevel.INFO,
|
27
|
+
is_silent=False,
|
28
|
+
stop_on_first_fail=False
|
29
|
+
)
|
30
|
+
|
31
|
+
# Run validation
|
32
|
+
validator = StaticValidator(config, console)
|
33
|
+
is_valid = validator.run()
|
34
|
+
|
35
|
+
if is_valid:
|
36
|
+
print("Validation Passed!")
|
37
|
+
|
38
|
+
Attributes:
|
39
|
+
__version__ (str): The current version of the package.
|
40
|
+
__all__ (list[str]): The list of public objects exposed by the package.
|
41
|
+
|
42
|
+
"""
|
43
|
+
|
44
|
+
from .config import AppConfig, ExitCode, LogLevel
|
45
|
+
from .core import StaticValidator
|
46
|
+
from .exceptions import RuleParsingError, ValidationFailedError
|
47
|
+
|
48
|
+
__all__ = [
|
49
|
+
"StaticValidator",
|
50
|
+
"AppConfig",
|
51
|
+
"ExitCode",
|
52
|
+
"LogLevel",
|
53
|
+
"ValidationFailedError",
|
54
|
+
"RuleParsingError",
|
55
|
+
]
|
56
|
+
|
57
|
+
__version__ = "0.1.3"
|
@@ -0,0 +1,20 @@
|
|
1
|
+
"""Enables running the validator as a package.
|
2
|
+
|
3
|
+
This file allows the package to be executed directly from the command line
|
4
|
+
using the ``-m`` flag with Python (e.g., ``python -m code_validator``). It
|
5
|
+
serves as the primary entry point that finds and invokes the command-line
|
6
|
+
interface logic defined in the `cli` module.
|
7
|
+
|
8
|
+
Example:
|
9
|
+
You can run the validator package like this from the project root:
|
10
|
+
|
11
|
+
.. code-block:: bash
|
12
|
+
|
13
|
+
python -m code_validator path/to/solution.py path/to/rules.json
|
14
|
+
|
15
|
+
"""
|
16
|
+
|
17
|
+
from .cli import run_from_cli
|
18
|
+
|
19
|
+
if __name__ == "__main__":
|
20
|
+
run_from_cli()
|
@@ -2,7 +2,11 @@
|
|
2
2
|
|
3
3
|
This module is responsible for parsing command-line arguments, setting up the
|
4
4
|
application configuration, and orchestrating the main validation workflow. It acts
|
5
|
-
as the primary entry point for user interaction
|
5
|
+
as the primary entry point for user interaction when the tool is called from
|
6
|
+
the terminal.
|
7
|
+
|
8
|
+
The main function, `run_from_cli`, handles the entire application lifecycle,
|
9
|
+
including robust top-level error handling to ensure meaningful exit codes.
|
6
10
|
"""
|
7
11
|
|
8
12
|
import argparse
|
@@ -19,8 +23,13 @@ from .output import Console, setup_logging
|
|
19
23
|
def setup_arg_parser() -> argparse.ArgumentParser:
|
20
24
|
"""Creates and configures the argument parser for the CLI.
|
21
25
|
|
26
|
+
This function defines all positional and optional arguments that the
|
27
|
+
`validate-code` command accepts, including their types, help messages,
|
28
|
+
and default values.
|
29
|
+
|
22
30
|
Returns:
|
23
|
-
|
31
|
+
argparse.ArgumentParser: A fully configured parser instance ready to
|
32
|
+
process command-line arguments.
|
24
33
|
"""
|
25
34
|
parser = argparse.ArgumentParser(
|
26
35
|
prog="validate-code",
|
@@ -32,7 +41,7 @@ def setup_arg_parser() -> argparse.ArgumentParser:
|
|
32
41
|
"-l",
|
33
42
|
"--log-level",
|
34
43
|
type=LogLevel,
|
35
|
-
choices=LogLevel,
|
44
|
+
choices=list(LogLevel),
|
36
45
|
default=LogLevel.WARNING,
|
37
46
|
help="Set the logging level (default: WARNING).",
|
38
47
|
)
|
@@ -45,14 +54,20 @@ def setup_arg_parser() -> argparse.ArgumentParser:
|
|
45
54
|
def run_from_cli() -> None:
|
46
55
|
"""Runs the full application lifecycle from the command line.
|
47
56
|
|
48
|
-
This
|
49
|
-
|
50
|
-
|
57
|
+
This is the main entry point for the `validate-code` script. It performs
|
58
|
+
the following steps:
|
59
|
+
1. Parses command-line arguments.
|
60
|
+
2. Initializes the logger, console, and configuration.
|
61
|
+
3. Instantiates and runs the `StaticValidator`.
|
62
|
+
4. Handles all top-level exceptions and exits with an appropriate status code.
|
63
|
+
|
64
|
+
Raises:
|
65
|
+
SystemExit: This function will always terminate the process with an
|
66
|
+
exit code defined in the `ExitCode` enum.
|
51
67
|
"""
|
52
68
|
parser = setup_arg_parser()
|
53
69
|
args = parser.parse_args()
|
54
70
|
|
55
|
-
# 1. Setup environment
|
56
71
|
logger = setup_logging(args.log_level)
|
57
72
|
console = Console(logger, is_silent=args.silent)
|
58
73
|
config = AppConfig(
|
@@ -63,7 +78,6 @@ def run_from_cli() -> None:
|
|
63
78
|
stop_on_first_fail=args.stop_on_first_fail,
|
64
79
|
)
|
65
80
|
|
66
|
-
# 2. Run main logic with robust error handling
|
67
81
|
try:
|
68
82
|
console.print(f"Starting validation for: {config.solution_path}", level=LogLevel.INFO)
|
69
83
|
validator = StaticValidator(config, console)
|
@@ -1,4 +1,9 @@
|
|
1
|
-
"""Provides utility functions for working with Python's Abstract Syntax Trees (AST).
|
1
|
+
"""Provides utility functions for working with Python's Abstract Syntax Trees (AST).
|
2
|
+
|
3
|
+
This module contains helper functions that perform common operations on AST nodes,
|
4
|
+
such as enriching the tree with parent references. These utilities are used by
|
5
|
+
various components of the validator to simplify complex tree analysis.
|
6
|
+
"""
|
2
7
|
|
3
8
|
import ast
|
4
9
|
|
@@ -15,7 +20,6 @@ def enrich_ast_with_parents(tree: ast.Module) -> None:
|
|
15
20
|
"""
|
16
21
|
for node in ast.walk(tree):
|
17
22
|
for child in ast.iter_child_nodes(node):
|
18
|
-
# Dynamically add a reference to the parent node.
|
19
23
|
child.parent = node
|
20
24
|
|
21
25
|
|
@@ -1,10 +1,11 @@
|
|
1
|
-
"""Defines the core component interfaces using Protocols.
|
1
|
+
"""Defines the core component interfaces for the validator using Protocols.
|
2
2
|
|
3
3
|
This module establishes the fundamental "contracts" for the main architectural
|
4
|
-
components
|
5
|
-
|
6
|
-
|
7
|
-
|
4
|
+
components: Rules, Selectors, and Constraints. By using `typing.Protocol`, we
|
5
|
+
ensure that any class conforming to these interfaces can be used interchangeably
|
6
|
+
by the system's factories and core engine. This enables a flexible and
|
7
|
+
decoupled plugin-style architecture, where new components can be added without
|
8
|
+
modifying the core logic.
|
8
9
|
"""
|
9
10
|
|
10
11
|
import ast
|
@@ -1,9 +1,10 @@
|
|
1
1
|
"""Contains factories for creating rule, selector, and constraint objects.
|
2
2
|
|
3
3
|
This module implements the Factory Method design pattern to decouple the core
|
4
|
-
validator engine from the concrete
|
5
|
-
responsible for parsing raw dictionary configurations from
|
6
|
-
the appropriate handler classes
|
4
|
+
validator engine from the concrete implementations of its components. Factories
|
5
|
+
are responsible for parsing raw dictionary configurations from the main JSON
|
6
|
+
rules file and instantiating the appropriate handler classes from the
|
7
|
+
`rules_library`.
|
7
8
|
"""
|
8
9
|
|
9
10
|
import dataclasses
|
@@ -1,8 +1,10 @@
|
|
1
1
|
"""Provides functionality to find and isolate specific scopes within an AST.
|
2
2
|
|
3
|
-
This module contains
|
4
|
-
|
5
|
-
|
3
|
+
This module contains a key helper function, `find_scope_node`, which is used
|
4
|
+
by `ScopedSelector` instances. Its purpose is to traverse the AST and return
|
5
|
+
a specific subtree (e.g., a function body or class body) based on the
|
6
|
+
`in_scope` configuration from a JSON rule. This allows rules to be applied
|
7
|
+
with high precision to specific parts of the source code.
|
6
8
|
"""
|
7
9
|
|
8
10
|
import ast
|
@@ -0,0 +1,151 @@
|
|
1
|
+
"""Defines all data structures and configuration models for the validator.
|
2
|
+
|
3
|
+
This module contains Enum classes for standardized codes and several frozen
|
4
|
+
dataclasses that represent the structured configuration loaded from JSON files
|
5
|
+
and command-line arguments. These models ensure type safety and provide a
|
6
|
+
clear "shape" for the application's data.
|
7
|
+
"""
|
8
|
+
|
9
|
+
from dataclasses import dataclass, field
|
10
|
+
from enum import IntEnum, StrEnum
|
11
|
+
from pathlib import Path
|
12
|
+
from typing import Any
|
13
|
+
|
14
|
+
|
15
|
+
class ExitCode(IntEnum):
|
16
|
+
"""Defines standardized exit codes for the command-line application."""
|
17
|
+
|
18
|
+
SUCCESS = 0
|
19
|
+
VALIDATION_FAILED = 1
|
20
|
+
FILE_NOT_FOUND = 2
|
21
|
+
JSON_ERROR = 3
|
22
|
+
UNEXPECTED_ERROR = 10
|
23
|
+
|
24
|
+
|
25
|
+
class LogLevel(StrEnum):
|
26
|
+
"""Defines the supported logging levels for the application."""
|
27
|
+
|
28
|
+
DEBUG = "DEBUG"
|
29
|
+
INFO = "INFO"
|
30
|
+
WARNING = "WARNING"
|
31
|
+
ERROR = "ERROR"
|
32
|
+
CRITICAL = "CRITICAL"
|
33
|
+
|
34
|
+
|
35
|
+
@dataclass(frozen=True)
|
36
|
+
class AppConfig:
|
37
|
+
"""Stores the main application configuration from CLI arguments.
|
38
|
+
|
39
|
+
Attributes:
|
40
|
+
solution_path: The file path to the Python solution to be validated.
|
41
|
+
rules_path: The file path to the JSON rules file.
|
42
|
+
log_level: The minimum logging level for console output.
|
43
|
+
is_silent: If True, suppresses all non-log output to stdout.
|
44
|
+
stop_on_first_fail: If True, halts validation after the first failed rule.
|
45
|
+
"""
|
46
|
+
|
47
|
+
solution_path: Path
|
48
|
+
rules_path: Path
|
49
|
+
log_level: LogLevel
|
50
|
+
is_silent: bool
|
51
|
+
stop_on_first_fail: bool
|
52
|
+
|
53
|
+
|
54
|
+
@dataclass(frozen=True)
|
55
|
+
class SelectorConfig:
|
56
|
+
"""Represents the configuration for a Selector component from a JSON rule.
|
57
|
+
|
58
|
+
This dataclass captures all possible keys within the "selector" block
|
59
|
+
of a JSON validation rule.
|
60
|
+
|
61
|
+
Attributes:
|
62
|
+
type: The type of the selector to be used (e.g., "function_def").
|
63
|
+
name: A generic name parameter used by many selectors (e.g., the name
|
64
|
+
of a function, class, or module).
|
65
|
+
node_type: The AST node type name for the `ast_node` selector.
|
66
|
+
in_scope: The scope in which to apply the selector.
|
67
|
+
"""
|
68
|
+
|
69
|
+
type: str
|
70
|
+
name: str | None = None
|
71
|
+
node_type: str | list[str] | None = None
|
72
|
+
in_scope: str | dict[str, Any] | None = None
|
73
|
+
|
74
|
+
|
75
|
+
@dataclass(frozen=True)
|
76
|
+
class ConstraintConfig:
|
77
|
+
"""Represents the configuration for a Constraint component from a JSON rule.
|
78
|
+
|
79
|
+
This dataclass captures all possible keys within the "constraint" block
|
80
|
+
of a JSON validation rule.
|
81
|
+
|
82
|
+
Attributes:
|
83
|
+
type: The type of the constraint to be applied (e.g., "is_required").
|
84
|
+
count: The exact number of nodes expected. Used by `is_required`.
|
85
|
+
parent_name: The expected parent class name. Used by `must_inherit_from`.
|
86
|
+
expected_type: The expected Python type name. Used by `must_be_type`.
|
87
|
+
allowed_names: A list of permitted names. Used by `name_must_be_in`.
|
88
|
+
allowed_values: A list of permitted literal values. Used by `value_must_be_in`.
|
89
|
+
names: A list of expected argument names. Used by `must_have_args`.
|
90
|
+
exact_match: A boolean flag for argument matching. Used by `must_have_args`.
|
91
|
+
"""
|
92
|
+
|
93
|
+
type: str
|
94
|
+
count: int | None = None
|
95
|
+
parent_name: str | None = None
|
96
|
+
expected_type: str | None = None
|
97
|
+
allowed_names: list[str] | None = None
|
98
|
+
allowed_values: list[Any] | None = None
|
99
|
+
names: list[str] | None = None
|
100
|
+
exact_match: bool | None = None
|
101
|
+
|
102
|
+
|
103
|
+
@dataclass(frozen=True)
|
104
|
+
class FullRuleCheck:
|
105
|
+
"""Represents the 'check' block within a full validation rule.
|
106
|
+
|
107
|
+
Attributes:
|
108
|
+
selector: The configuration for the selector component.
|
109
|
+
constraint: The configuration for the constraint component.
|
110
|
+
"""
|
111
|
+
|
112
|
+
selector: SelectorConfig
|
113
|
+
constraint: ConstraintConfig
|
114
|
+
|
115
|
+
|
116
|
+
@dataclass(frozen=True)
|
117
|
+
class ShortRuleConfig:
|
118
|
+
"""Represents a 'short' (pre-defined) validation rule from JSON.
|
119
|
+
|
120
|
+
Attributes:
|
121
|
+
rule_id: The unique integer identifier for the rule.
|
122
|
+
type: The string identifier for the short rule (e.g., "check_syntax").
|
123
|
+
message: The error message to display if the rule fails.
|
124
|
+
params: A dictionary of optional parameters for the rule.
|
125
|
+
"""
|
126
|
+
|
127
|
+
rule_id: int
|
128
|
+
type: str
|
129
|
+
message: str
|
130
|
+
params: dict[str, Any] = field(default_factory=dict)
|
131
|
+
|
132
|
+
|
133
|
+
@dataclass(frozen=True)
|
134
|
+
class FullRuleConfig:
|
135
|
+
"""Represents a 'full' (custom) validation rule with a selector and constraint.
|
136
|
+
|
137
|
+
Attributes:
|
138
|
+
rule_id: The unique integer identifier for the rule.
|
139
|
+
message: The error message to display if the rule fails.
|
140
|
+
check: An object containing the selector and constraint configurations.
|
141
|
+
is_critical: If True, validation halts if this rule fails.
|
142
|
+
"""
|
143
|
+
|
144
|
+
rule_id: int
|
145
|
+
message: str
|
146
|
+
check: FullRuleCheck
|
147
|
+
is_critical: bool = False
|
148
|
+
|
149
|
+
|
150
|
+
# A type alias representing any possible rule configuration object.
|
151
|
+
ValidationRuleConfig = ShortRuleConfig | FullRuleConfig
|