Component Architecture¶
This section documents the core architectural components, such as protocols and factories.
Component Interfaces
Defines the core component interfaces for the validator using Protocols.
This module establishes the fundamental “contracts” for the main architectural components: Rules, Selectors, and Constraints. By using typing.Protocol, we ensure that any class conforming to these interfaces can be used interchangeably by the system’s factories and core engine. This enables a flexible and decoupled plugin-style architecture, where new components can be added without modifying the core logic.
- class code_validator.components.definitions.Constraint(*args, **kwargs)¶
An interface for objects that apply a condition to a set of AST nodes.
A Constraint takes the list of nodes found by a Selector and checks if they satisfy a specific condition (e.g., the list must not be empty, the node must inherit from a specific class).
- check(nodes: list[AST]) bool¶
Checks if the given list of nodes satisfies the constraint.
- Parameters:
nodes – A list of AST nodes provided by a Selector.
- Returns:
True if the constraint is satisfied, False otherwise.
- class code_validator.components.definitions.Rule(*args, **kwargs)¶
An interface for any complete, executable validation rule.
A Rule represents a single, self-contained validation check. It can be a “short” rule (like a linter check) or a “full” rule that internally uses a Selector and a Constraint. The core validator engine interacts with objects conforming to this protocol.
- config¶
The dataclass object holding the configuration for this rule, parsed from the JSON file.
- typo_suggestion¶
Optional typo suggestion message for user display.
- Type:
str | None
- execute(tree: Module | None, source_code: str | None = None) bool¶
Executes the validation rule.
Depending on the rule type, this method might operate on the AST, the raw source code, or both.
- Parameters:
tree – The full AST of the source code (for structural checks).
source_code – The raw source code string (e.g., for linter checks).
- Returns:
True if the validation check passes, False otherwise.
- class code_validator.components.definitions.Selector(*args, **kwargs)¶
An interface for objects that find and select specific nodes from an AST.
A Selector’s main responsibility is to traverse the Abstract Syntax Tree (AST) of a Python source file and return a list of nodes that match a specific criterion (e.g., all function definitions, all import statements).
- select(tree: Module) list[AST]¶
Selects and returns a list of relevant AST nodes from the tree.
- Parameters:
tree – The full, parsed AST of the source code to be searched.
- Returns:
A list of ast.AST nodes that match the selector’s criteria. An empty list should be returned if no matching nodes are found.
Component Factories
Contains factories for creating rule, selector, and constraint objects.
This module implements the Factory Method design pattern to decouple the core validator engine from the concrete implementations of its components. Factories are responsible for parsing raw dictionary configurations from the main JSON rules file and instantiating the appropriate handler classes from the rules_library.
- class code_validator.components.factories.ConstraintFactory¶
Creates constraint objects from raw dictionary configuration.
This factory is responsible for instantiating the correct Constraint object based on the ‘type’ field in a rule’s constraint configuration block. Each concrete constraint specializes in applying a specific logical check to a list of AST nodes. This class uses a static create method.
- static create(config: ConstraintConfig) Constraint¶
Creates a specific constraint instance based on its type.
This method uses the ‘type’ field from the constraint configuration to determine which concrete Constraint class to instantiate.
- Parameters:
config – The ‘constraint’ block from a JSON rule.
- Returns:
An instance of a class that conforms to the Constraint protocol.
- class code_validator.components.factories.RuleFactory(console: Console)¶
Creates rule handler objects from raw dictionary configuration.
This is the main factory that acts as an entry point for parsing the ‘validation_rules’ list from a JSON file. It determines whether a rule is a “short” pre-defined type or a “full” custom rule and delegates the creation of its components to other specialized factories.
- _selector_factory¶
A factory for creating selector objects.
- Type:
- _constraint_factory¶
A factory for creating constraint objects.
- Type:
- create(rule_config: dict[str, Any]) Rule¶
Creates a specific rule instance based on its configuration.
This method acts as a dispatcher. It determines whether the configuration describes a “short” pre-defined rule or a “full” custom rule with a selector/constraint pair, and then delegates to the appropriate creation logic.
- Parameters:
rule_config – A dictionary parsed from the JSON rules file.
- Returns:
An instance of an object that conforms to the Rule protocol.
- Raises:
RuleParsingError – If the rule configuration is invalid, missing required keys, or specifies an unknown type.
- class code_validator.components.factories.SelectorFactory¶
Creates selector objects from raw dictionary configuration.
This factory is responsible for instantiating the correct Selector object based on the ‘type’ field in a rule’s selector configuration block. Each concrete selector specializes in finding a specific type of AST node. This class uses a static create method as it does not need to maintain any state.
- static create(config: SelectorConfig) Selector¶
Creates a specific selector instance based on its type.
This method uses the ‘type’ field from the selector configuration to determine which concrete Selector class to instantiate.
- Parameters:
config – The ‘selector’ block from a JSON rule.
- Returns:
An instance of a class that conforms to the Selector protocol.
Helper Modules
Provides functionality to find and isolate specific scopes within an AST.
This module contains a key helper function, find_scope_node, which is used by ScopedSelector instances. Its purpose is to traverse the AST and return a specific subtree (e.g., a function body or class body) based on the in_scope configuration from a JSON rule. This allows rules to be applied with high precision to specific parts of the source code.
- code_validator.components.scope_handler.find_scope_node(tree: Module, scope_config: dict[str, Any]) AST | None¶
Finds a specific scope node (class or function) within the AST.
This function traverses the AST to locate a node that matches the provided scope configuration. It supports finding global functions, classes, and methods within classes.
- Parameters:
tree – The root of the AST (the module object).
scope_config – A dictionary defining the desired scope. Expected keys: - “function”: name of a global function. - “class”: name of a class. - “method”: name of a method (must be used with “class”).
- Returns:
The found ast.AST node (either ast.ClassDef or ast.FunctionDef) that represents the desired scope, or None if the scope is not found.
Example
>>> # To find the scope of 'my_func' in 'MyClass': >>> scope_config = {"class": "MyClass", "method": "my_func"} >>> find_scope_node(my_ast_tree, scope_config) <ast.FunctionDef object at ...>
Provides utility functions for working with Python’s Abstract Syntax Trees (AST).
This module contains helper functions that perform common operations on AST nodes, such as enriching the tree with parent references. These utilities are used by various components of the validator to simplify complex tree analysis.
- code_validator.components.ast_utils.enrich_ast_with_parents(tree: Module) None¶
Walks the AST and adds a ‘parent’ attribute to each node.
This function mutates the AST in-place, making it easier to traverse upwards or determine the context of a specific node. This is a crucial preprocessing step for many complex validation rules.
- Parameters:
tree – The root node of the AST (typically an ast.Module object) to enrich.
- code_validator.components.ast_utils.get_full_name(node: AST) str | None¶
A helper function to recursively build a full attribute name from an AST node.
For example, for an ast.Attribute node representing foo.bar.baz, this function will return the string “foo.bar.baz”.
- Parameters:
node – The AST node to extract the name from.
- Returns:
The full, dot-separated name as a string, or None if a name cannot be constructed.