On this page
Python linter using tree-sitter AST parsing to detect library boundary violations including forbidden imports and stdout/logging usage.
#rlsbl.lint.python_ast
#rlsbl.lint.python_ast
Python linter using tree-sitter AST parsing to detect library boundary violations including forbidden imports and stdout/logging usage.
#ImportRecord
| Field | Type | Default |
|---|---|---|
top_level | str | |
full_path | str | |
filepath | str | |
line | int | |
guarded | bool | False |
type_checking | bool | False |
#_node_line
def _node_line(node)Return 1-based line number for a tree-sitter node.
#_is_in_try_except_import_error
def _is_in_try_except_import_error(node)Check if an import node is inside a try body protected by except ImportError/ModuleNotFoundError.
Walks up the parent chain looking for a try_statement ancestor where:
- The import is in the try body (not inside an except_clause's block)
- At least one except_clause catches ImportError or ModuleNotFoundError
Returns True if ANY ancestor try_statement satisfies both conditions.
#_try_catches_import_error
def _try_catches_import_error(try_node, error_names)Check if a try_statement has an except_clause catching ImportError/ModuleNotFoundError.
#_is_in_type_checking_block
def _is_in_type_checking_block(node)Check if an import node is inside an if TYPE_CHECKING: block.
Walks up the parent chain looking for an if_statement ancestor whose condition is:
- An identifier node with text
TYPE_CHECKING, OR - An attribute node whose last identifier is
TYPE_CHECKING
(for typing.TYPE_CHECKING)
Returns True if found, False otherwise.
#_collect_all_imports
def _collect_all_imports(tree, filepath)Walk AST and collect all imported module names with full paths.
Returns a set of ImportRecord with top_level, full_path, filepath, line, guarded, and type_checking fields. top_level is the first component of the dotted path (e.g., "orxt"). full_path is the complete dotted module path (e.g., "orxt.protocols"). Imports inside try/except ImportError blocks are marked guarded=True. Imports inside if TYPE_CHECKING: blocks are marked type_checking=True.
#_check_forbidden_imports
def _check_forbidden_imports(tree, filepath, config)Walk AST for import_statement and import_from_statement nodes.
#child_by_field
def child_by_field(node, field_name)Find the module name in an import_from_statement.
tree-sitter-python represents 'from foo import bar' with the module as a dotted_name or relative_import child before the 'import' keyword.
#_check_stdout
def _check_stdout(tree, filepath, config)Detect print(), sys.stdout/stderr.write(), and logging.* calls.
#_check_entry_points
def _check_entry_points(project_path, config)Check pyproject.toml for CLI entry point declarations.
#_always_terminates
def _always_terminates(node)Return True if the given node unconditionally terminates its enclosing block.
A node always terminates if:
- It is a return, raise, break, or continue statement.
- It is a block whose last child always terminates.
- It is an if_statement with an else_clause where the if body, all elif
bodies, and the else body all always terminate.
#_terminator_label
def _terminator_label(node)Return a human-readable label for the terminating construct.
#_check_unreachable_code
def _check_unreachable_code(tree, filepath)Detect unreachable statements in block nodes.
Walks all block nodes in the tree. Within each block, if a child statement unconditionally terminates (return, raise, break, continue, or exhaustive if/else with all branches terminating), any subsequent sibling statements are flagged as unreachable.
Skips nested function and class definitions -- a return inside a nested function does not make the outer code unreachable.
#PythonAstLinter
Python linter using tree-sitter AST analysis.
#lint
def lint(self, project_path: str, config: LanguageLintConfig) -> list[LintResult]#scan_imports
def scan_imports(self, project_path: str, exclude_dirs: list[str] | None=None) -> set[ImportRecord]Collect all imported module names from Python files.
Returns a set of ImportRecord with top_level, full_path, filepath, line, guarded, and type_checking fields. Guarded imports are those inside try/except ImportError blocks. TYPE_CHECKING imports are those inside if TYPE_CHECKING: blocks.