python-code-validator 0.1.2__tar.gz → 0.2.1__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.
Files changed (37) hide show
  1. {python_code_validator-0.1.2/src/python_code_validator.egg-info → python_code_validator-0.2.1}/PKG-INFO +13 -30
  2. {python_code_validator-0.1.2 → python_code_validator-0.2.1}/README.md +2 -2
  3. python_code_validator-0.2.1/pyproject.toml +120 -0
  4. python_code_validator-0.2.1/src/code_validator/__init__.py +57 -0
  5. python_code_validator-0.2.1/src/code_validator/__main__.py +20 -0
  6. python_code_validator-0.2.1/src/code_validator/cli.py +112 -0
  7. {python_code_validator-0.1.2 → python_code_validator-0.2.1}/src/code_validator/components/ast_utils.py +6 -2
  8. {python_code_validator-0.1.2 → python_code_validator-0.2.1}/src/code_validator/components/definitions.py +6 -5
  9. {python_code_validator-0.1.2 → python_code_validator-0.2.1}/src/code_validator/components/factories.py +35 -16
  10. {python_code_validator-0.1.2 → python_code_validator-0.2.1}/src/code_validator/components/scope_handler.py +5 -3
  11. python_code_validator-0.2.1/src/code_validator/config.py +152 -0
  12. python_code_validator-0.2.1/src/code_validator/core.py +223 -0
  13. python_code_validator-0.2.1/src/code_validator/output.py +236 -0
  14. {python_code_validator-0.1.2 → python_code_validator-0.2.1}/src/code_validator/rules_library/basic_rules.py +23 -16
  15. {python_code_validator-0.1.2 → python_code_validator-0.2.1}/src/code_validator/rules_library/constraint_logic.py +301 -257
  16. {python_code_validator-0.1.2 → python_code_validator-0.2.1}/src/code_validator/rules_library/selector_nodes.py +66 -5
  17. {python_code_validator-0.1.2 → python_code_validator-0.2.1/src/python_code_validator.egg-info}/PKG-INFO +13 -30
  18. {python_code_validator-0.1.2 → python_code_validator-0.2.1}/src/python_code_validator.egg-info/requires.txt +2 -2
  19. {python_code_validator-0.1.2 → python_code_validator-0.2.1}/tests/test_validator.py +9 -10
  20. python_code_validator-0.1.2/pyproject.toml +0 -62
  21. python_code_validator-0.1.2/src/code_validator/__init__.py +0 -25
  22. python_code_validator-0.1.2/src/code_validator/__main__.py +0 -11
  23. python_code_validator-0.1.2/src/code_validator/cli.py +0 -88
  24. python_code_validator-0.1.2/src/code_validator/config.py +0 -99
  25. python_code_validator-0.1.2/src/code_validator/core.py +0 -100
  26. python_code_validator-0.1.2/src/code_validator/output.py +0 -90
  27. {python_code_validator-0.1.2 → python_code_validator-0.2.1}/LICENSE +0 -0
  28. {python_code_validator-0.1.2 → python_code_validator-0.2.1}/setup.cfg +0 -0
  29. {python_code_validator-0.1.2 → python_code_validator-0.2.1}/src/code_validator/components/__init__.py +0 -0
  30. {python_code_validator-0.1.2 → python_code_validator-0.2.1}/src/code_validator/exceptions.py +0 -0
  31. {python_code_validator-0.1.2 → python_code_validator-0.2.1}/src/code_validator/rules_library/__init__.py +0 -0
  32. {python_code_validator-0.1.2 → python_code_validator-0.2.1}/src/python_code_validator.egg-info/SOURCES.txt +0 -0
  33. {python_code_validator-0.1.2 → python_code_validator-0.2.1}/src/python_code_validator.egg-info/dependency_links.txt +0 -0
  34. {python_code_validator-0.1.2 → python_code_validator-0.2.1}/src/python_code_validator.egg-info/entry_points.txt +0 -0
  35. {python_code_validator-0.1.2 → python_code_validator-0.2.1}/src/python_code_validator.egg-info/top_level.txt +0 -0
  36. {python_code_validator-0.1.2 → python_code_validator-0.2.1}/tests/test_components.py +0 -0
  37. {python_code_validator-0.1.2 → python_code_validator-0.2.1}/tests/test_scope_handler.py +0 -0
@@ -1,49 +1,32 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-code-validator
3
- Version: 0.1.2
4
- Summary: A flexible framework for static validation of Python code based on JSON rules.
3
+ Version: 0.2.1
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
- License: MIT License
7
-
8
- Copyright (c) 2025 Ivan Kovach
9
-
10
- Permission is hereby granted, free of charge, to any person obtaining a copy
11
- of this software and associated documentation files (the "Software"), to deal
12
- in the Software without restriction, including without limitation the rights
13
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
- copies of the Software, and to permit persons to whom the Software is
15
- furnished to do so, subject to the following conditions:
16
-
17
- The above copyright notice and this permission notice shall be included in all
18
- copies or substantial portions of the Software.
19
-
20
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
- SOFTWARE.
27
-
6
+ License-Expression: MIT
28
7
  Project-URL: Homepage, https://github.com/Qu1nel/PythonCodeValidator
29
8
  Project-URL: Documentation, https://pythoncodevalidator.readthedocs.io/en/latest/
30
9
  Project-URL: Bug Tracker, https://github.com/Qu1nel/PythonCodeValidator/issues
31
- Keywords: validation,linter,static analysis,testing,education
32
- Classifier: Development Status :: 3 - Alpha
10
+ Keywords: validation,linter,static analysis,testing,education,ast
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Intended Audience :: Education
33
14
  Classifier: Programming Language :: Python :: 3
34
15
  Classifier: Programming Language :: Python :: 3.11
35
16
  Classifier: Programming Language :: Python :: 3.12
36
- Classifier: License :: OSI Approved :: MIT License
37
17
  Classifier: Operating System :: OS Independent
18
+ Classifier: Topic :: Software Development :: Quality Assurance
19
+ Classifier: Topic :: Software Development :: Testing
20
+ Classifier: Topic :: Education
38
21
  Requires-Python: >=3.11
39
22
  Description-Content-Type: text/markdown
40
23
  License-File: LICENSE
24
+ Requires-Dist: flake8>=7.0.0
41
25
  Provides-Extra: dev
42
26
  Requires-Dist: ruff>=0.4.0; extra == "dev"
43
- Requires-Dist: flake8>=7.0.0; extra == "dev"
44
27
  Requires-Dist: build; extra == "dev"
45
28
  Requires-Dist: twine; extra == "dev"
46
- Requires-Dist: coverage>=7.5.0; extra == "dev"
29
+ Requires-Dist: coverage[toml]>=7.5.0; extra == "dev"
47
30
  Provides-Extra: docs
48
31
  Requires-Dist: sphinx>=7.0.0; extra == "docs"
49
32
  Requires-Dist: furo; extra == "docs"
@@ -282,7 +265,7 @@ Validation failed.
282
265
  **[Read the Docs](https://[your-project].readthedocs.io)**.
283
266
  - **Developer's Guide**: For a deep dive into the architecture, see the
284
267
  **[How It Works guide](./docs/how_it_works/index.md)**.
285
- - **Interactive AI-Powered Docs**: *(Coming Soon)* An interactive documentation experience.
268
+ - **Interactive AI-Powered Docs**: **[DeepWiki](https://deepwiki.com/Qu1nel/PythonCodeValidator)**.
286
269
 
287
270
  ## 🤝 Contributing
288
271
 
@@ -229,7 +229,7 @@ Validation failed.
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
231
  **[How It Works guide](./docs/how_it_works/index.md)**.
232
- - **Interactive AI-Powered Docs**: *(Coming Soon)* An interactive documentation experience.
232
+ - **Interactive AI-Powered Docs**: **[DeepWiki](https://deepwiki.com/Qu1nel/PythonCodeValidator)**.
233
233
 
234
234
  ## 🤝 Contributing
235
235
 
@@ -253,4 +253,4 @@ Email: **[covach.qn@gmail.com](mailto:covach.qn@gmail.com)** Telegram: **[@qnlln
253
253
 
254
254
  <br/>
255
255
 
256
- <p align="right"><a href="./LICENSE">MIT</a> © <a href="https://github.com/Qu1nel/">Ivan Kovach</a></p>
256
+ <p align="right"><a href="./LICENSE">MIT</a> © <a href="https://github.com/Qu1nel/">Ivan Kovach</a></p>
@@ -0,0 +1,120 @@
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.2.1"
14
+ description = "A flexible, AST-based framework for static validation of Python code using declarative JSON rules."
15
+ keywords = ["validation", "linter", "static analysis", "testing", "education", "ast"]
16
+ authors = [{ name = "Qu1nel", email = "covach.qn@gmail.com" }]
17
+ readme = "README.md"
18
+ requires-python = ">=3.11"
19
+ license-files = ["LICEN[CS]E*"]
20
+ license = "MIT"
21
+ classifiers = [
22
+ "Development Status :: 4 - Beta",
23
+ "Intended Audience :: Developers",
24
+ "Intended Audience :: Education",
25
+ "Programming Language :: Python :: 3",
26
+ "Programming Language :: Python :: 3.11",
27
+ "Programming Language :: Python :: 3.12",
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
+
44
+ [project.scripts]
45
+ validate-code = "code_validator.cli:run_from_cli"
46
+
47
+
48
+ [project.optional-dependencies]
49
+ dev = [
50
+ "ruff>=0.4.0",
51
+ "build",
52
+ "twine",
53
+ "coverage[toml]>=7.5.0",
54
+ ]
55
+ docs = [
56
+ "sphinx>=7.0.0",
57
+ "furo",
58
+ "myst-parser",
59
+ "sphinx-design",
60
+ ]
61
+
62
+ # ==============================================================================
63
+ # Tool Configuration
64
+ # ==============================================================================
65
+
66
+ [tool.ruff]
67
+ line-length = 120
68
+ exclude = [
69
+ ".venv",
70
+ "build",
71
+ "dist",
72
+ "src/python_code_validator.egg-info",
73
+ "tests/fixtures",
74
+ ]
75
+
76
+ [tool.ruff.lint]
77
+ select = [
78
+ "E", # pycodestyle errors
79
+ "W", # pycodestyle warnings
80
+ "F", # pyflakes
81
+ "I", # isort
82
+ "B", # flake8-bugbear
83
+ "C4", # flake8-comprehensions
84
+ "D", # pydocstyle
85
+ ]
86
+ ignore = []
87
+
88
+ [tool.ruff.lint.per-file-ignores]
89
+ "tests/*" = [
90
+ "D100", # Missing docstring in public module
91
+ "D101", # Missing docstring in public class
92
+ "D102", # Missing docstring in public method
93
+ "D103", # Missing docstring in public function
94
+ "D104", # Missing docstring in public package
95
+ "D107", # Missing docstring in __init__
96
+ ]
97
+ "src/code_validator/components/__init__.py" = ["D104"]
98
+ "src/code_validator/rules_library/__init__.py" = ["D104"]
99
+ "src/code_validator/components/factories.py" = ["D107"]
100
+
101
+ [tool.ruff.lint.pydocstyle]
102
+ convention = "google"
103
+
104
+ [tool.ruff.lint.isort]
105
+ known-first-party = ["code_validator", "tests"]
106
+
107
+ [tool.ruff.format]
108
+ quote-style = "double"
109
+
110
+ [tool.coverage.run]
111
+ omit = [
112
+ "src/code_validator/__main__.py",
113
+ "src/code_validator/cli.py",
114
+ "tests/*",
115
+ "*/__init__.py",
116
+ ]
117
+
118
+ [tool.coverage.report]
119
+ fail_under = 85
120
+ 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.2.1"
@@ -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()
@@ -0,0 +1,112 @@
1
+ """Defines the command-line interface for the code validator.
2
+
3
+ This module is responsible for parsing command-line arguments, setting up the
4
+ application configuration, and orchestrating the main validation workflow. It acts
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.
10
+ """
11
+
12
+ import argparse
13
+ import sys
14
+ from pathlib import Path
15
+
16
+ from . import __version__
17
+ from .config import AppConfig, ExitCode, LogLevel
18
+ from .core import StaticValidator
19
+ from .exceptions import CodeValidatorError
20
+ from .output import Console, setup_logging
21
+
22
+
23
+ def setup_arg_parser() -> argparse.ArgumentParser:
24
+ """Creates and configures the argument parser for the CLI.
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
+
30
+ Returns:
31
+ argparse.ArgumentParser: A fully configured parser instance ready to
32
+ process command-line arguments.
33
+ """
34
+ parser = argparse.ArgumentParser(
35
+ prog="validate-code",
36
+ description="Validates a Python source file against a set of JSON rules.",
37
+ )
38
+
39
+ parser.add_argument("solution_path", type=Path, help="Path to the Python solution file to validate.")
40
+ parser.add_argument("rules_path", type=Path, help="Path to the JSON file with validation rules.")
41
+
42
+ parser.add_argument(
43
+ "--log",
44
+ type=LogLevel,
45
+ default=LogLevel.ERROR,
46
+ help=("Set the logging level for stderr (TRACE, DEBUG, INFO, WARNING, ERROR, CRITICAL). Default: ERROR."),
47
+ )
48
+ parser.add_argument(
49
+ "--quiet", action="store_true", help="Suppress all stdout output (validation errors and final verdict)."
50
+ )
51
+ parser.add_argument("--no-verdict", action="store_true", help="Suppress stdout output verdict, show failed rules.")
52
+ parser.add_argument("--stop-on-first-fail", action="store_true", help="Stop after the first failed rule.")
53
+ parser.add_argument("--version", "-v", action="version", version=f"%(prog)s {__version__}")
54
+ return parser
55
+
56
+
57
+ def run_from_cli() -> None:
58
+ """Runs the full application lifecycle from the command line.
59
+
60
+ This is the main entry point for the `validate-code` script. It performs
61
+ the following steps:
62
+ 1. Parses command-line arguments.
63
+ 2. Initializes the logger, console, and configuration.
64
+ 3. Instantiates and runs the `StaticValidator`.
65
+ 4. Handles all top-level exceptions and exits with an appropriate status code.
66
+
67
+ Raises:
68
+ SystemExit: This function will always terminate the process with an
69
+ exit code defined in the `ExitCode` enum.
70
+ """
71
+ parser = setup_arg_parser()
72
+ args = parser.parse_args()
73
+
74
+ logger = setup_logging(args.log)
75
+ console = Console(logger, is_quiet=args.quiet, show_verdict=not args.no_verdict)
76
+ console.print(f"Level of logging: {args.log}", level=LogLevel.DEBUG)
77
+ config = AppConfig(
78
+ solution_path=args.solution_path,
79
+ rules_path=args.rules_path,
80
+ log_level=args.log,
81
+ is_quiet=args.quiet,
82
+ stop_on_first_fail=args.stop_on_first_fail,
83
+ )
84
+ console.print(f"Config is: {config}", level=LogLevel.TRACE)
85
+
86
+ try:
87
+ console.print(f"Starting validation for: {config.solution_path}", level=LogLevel.INFO)
88
+ validator = StaticValidator(config, console)
89
+
90
+ console.print("Start of validation..", level=LogLevel.TRACE)
91
+ is_valid = validator.run()
92
+ console.print(f"End of validation with result: {is_valid = }", level=LogLevel.TRACE)
93
+
94
+ if is_valid:
95
+ console.print("Validation successful.", level=LogLevel.INFO, is_verdict=True)
96
+ sys.exit(ExitCode.SUCCESS)
97
+ else:
98
+ console.print("Validation failed.", level=LogLevel.INFO, is_verdict=True)
99
+ sys.exit(ExitCode.VALIDATION_FAILED)
100
+
101
+ except CodeValidatorError as e:
102
+ console.print("Error: Internal Error of validator!", level=LogLevel.CRITICAL)
103
+ logger.exception(f"Traceback for CodeValidatorError: {e}")
104
+ sys.exit(ExitCode.VALIDATION_FAILED)
105
+ except FileNotFoundError as e:
106
+ console.print(f"Error: File not found - {e.filename}!", level=LogLevel.CRITICAL)
107
+ logger.exception(f"Traceback for FileNotFoundError: {e}")
108
+ sys.exit(ExitCode.FILE_NOT_FOUND)
109
+ except Exception as e:
110
+ console.print(f"An unexpected error occurred: {e.__class__.__name__}!", level=LogLevel.CRITICAL)
111
+ logger.exception(f"Traceback for unexpected error: {e}")
112
+ sys.exit(ExitCode.UNEXPECTED_ERROR)
@@ -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 of the validator: Rules, Selectors, and Constraints. By using
5
- Protocols, we ensure that any class conforming to these interfaces can be used
6
- interchangeably by the system's factories and core engine, enabling a flexible
7
- and decoupled plugin-style architecture.
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,17 +1,18 @@
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 implementation of rules. Factories are
5
- responsible for parsing raw dictionary configurations from JSON and instantiating
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
10
11
  from typing import Any, Type, TypeVar
11
12
 
12
- from ..config import ConstraintConfig, FullRuleCheck, FullRuleConfig, SelectorConfig, ShortRuleConfig
13
+ from ..config import ConstraintConfig, FullRuleCheck, FullRuleConfig, LogLevel, SelectorConfig, ShortRuleConfig
13
14
  from ..exceptions import RuleParsingError
14
- from ..output import Console
15
+ from ..output import Console, log_initialization
15
16
  from ..rules_library.basic_rules import CheckLinterRule, CheckSyntaxRule, FullRuleHandler
16
17
  from ..rules_library.constraint_logic import (
17
18
  IsForbiddenConstraint,
@@ -70,6 +71,7 @@ class RuleFactory:
70
71
  _constraint_factory (ConstraintFactory): A factory for creating constraint objects.
71
72
  """
72
73
 
74
+ @log_initialization(level=LogLevel.TRACE)
73
75
  def __init__(self, console: Console):
74
76
  """Initializes the RuleFactory.
75
77
 
@@ -100,8 +102,10 @@ class RuleFactory:
100
102
  required keys, or specifies an unknown type.
101
103
  """
102
104
  rule_id = rule_config.get("rule_id")
105
+ self._console.print(f"Start parsing rule ({rule_id}):\n{rule_config}", level=LogLevel.TRACE)
103
106
  try:
104
107
  if "type" in rule_config:
108
+ self._console.print(f"Rule {rule_id} is shorted rule - {rule_config['type']}", level=LogLevel.DEBUG)
105
109
  config = _create_dataclass_from_dict(ShortRuleConfig, rule_config)
106
110
  return self._create_short_rule(config)
107
111
 
@@ -109,20 +113,31 @@ class RuleFactory:
109
113
  raw_selector_cfg = rule_config["check"]["selector"]
110
114
  raw_constraint_cfg = rule_config["check"]["constraint"]
111
115
 
112
- selector = self._selector_factory.create(raw_selector_cfg)
113
- constraint = self._constraint_factory.create(raw_constraint_cfg)
114
-
115
116
  selector_cfg = _create_dataclass_from_dict(SelectorConfig, raw_selector_cfg)
116
117
  constraint_cfg = _create_dataclass_from_dict(ConstraintConfig, raw_constraint_cfg)
118
+
119
+ selector = self._selector_factory.create(selector_cfg)
120
+ constraint = self._constraint_factory.create(constraint_cfg)
121
+
122
+ self._console.print(
123
+ f"Rule {rule_id} is general rule with: selector - "
124
+ f"{selector_cfg.type}, constraint - {raw_constraint_cfg['type']}",
125
+ level=LogLevel.DEBUG,
126
+ )
127
+
117
128
  check_cfg = FullRuleCheck(selector=selector_cfg, constraint=constraint_cfg)
129
+ self._console.print(f"Create FullRuleCheck: {check_cfg}", level=LogLevel.TRACE)
130
+
118
131
  config = FullRuleConfig(
119
132
  rule_id=rule_config["rule_id"],
120
133
  message=rule_config["message"],
121
134
  check=check_cfg,
122
135
  is_critical=rule_config.get("is_critical", False),
123
136
  )
137
+ self._console.print(f"Create FullRuleConfig: {config}", level=LogLevel.TRACE)
124
138
  return FullRuleHandler(config, selector, constraint, self._console)
125
139
  else:
140
+ self._console.print(f"Invalid syntax of rule: {rule_id}", level=LogLevel.WARNING)
126
141
  raise RuleParsingError("Rule must contain 'type' or 'check' key.", rule_id)
127
142
  except (TypeError, KeyError, RuleParsingError) as e:
128
143
  raise RuleParsingError(f"Invalid config for rule '{rule_id}': {e}", rule_id) from e
@@ -164,21 +179,23 @@ class SelectorFactory:
164
179
  any state.
165
180
  """
166
181
 
182
+ @log_initialization(level=LogLevel.TRACE)
183
+ def __init__(self) -> None:
184
+ pass
185
+
167
186
  @staticmethod
168
- def create(selector_config: dict[str, Any]) -> Selector:
187
+ def create(config: SelectorConfig) -> Selector:
169
188
  """Creates a specific selector instance based on its type.
170
189
 
171
190
  This method uses the 'type' field from the selector configuration
172
191
  to determine which concrete Selector class to instantiate.
173
192
 
174
193
  Args:
175
- selector_config: The 'selector' block from a JSON rule.
194
+ config: The 'selector' block from a JSON rule.
176
195
 
177
196
  Returns:
178
197
  An instance of a class that conforms to the Selector protocol.
179
198
  """
180
- config = _create_dataclass_from_dict(SelectorConfig, selector_config)
181
-
182
199
  match config.type:
183
200
  case "function_def":
184
201
  return FunctionDefSelector(name=config.name, in_scope_config=config.in_scope)
@@ -209,21 +226,23 @@ class ConstraintFactory:
209
226
  to a list of AST nodes. This class uses a static `create` method.
210
227
  """
211
228
 
229
+ @log_initialization(level=LogLevel.TRACE)
230
+ def __init__(self) -> None:
231
+ pass
232
+
212
233
  @staticmethod
213
- def create(constraint_config: dict[str, Any]) -> Constraint:
234
+ def create(config: ConstraintConfig) -> Constraint:
214
235
  """Creates a specific constraint instance based on its type.
215
236
 
216
237
  This method uses the 'type' field from the constraint configuration
217
238
  to determine which concrete Constraint class to instantiate.
218
239
 
219
240
  Args:
220
- constraint_config: The 'constraint' block from a JSON rule.
241
+ config: The 'constraint' block from a JSON rule.
221
242
 
222
243
  Returns:
223
244
  An instance of a class that conforms to the Constraint protocol.
224
245
  """
225
- config = _create_dataclass_from_dict(ConstraintConfig, constraint_config)
226
-
227
246
  match config.type:
228
247
  case "is_required":
229
248
  return IsRequiredConstraint(count=config.count)
@@ -1,8 +1,10 @@
1
1
  """Provides functionality to find and isolate specific scopes within an AST.
2
2
 
3
- This module contains helper functions that are used by ScopedSelectors to narrow
4
- down their search area from the entire module to a specific function, class,
5
- or method, based on the `in_scope` configuration from a JSON rule.
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