rlsbl v0.92.0 /rlsbl.lint.python_ast
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

ImportRecord
FieldTypeDefault
top_levelstr
full_pathstr
filepathstr
lineint
guardedboolFalse
type_checkingboolFalse

#_node_line

python
def _node_line(node)

Return 1-based line number for a tree-sitter node.

#_is_in_try_except_import_error

python
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:

  1. The import is in the try body (not inside an except_clause's block)
  2. At least one except_clause catches ImportError or ModuleNotFoundError

Returns True if ANY ancestor try_statement satisfies both conditions.

#_try_catches_import_error

python
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

python
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

python
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

python
def _check_forbidden_imports(tree, filepath, config)

Walk AST for import_statement and import_from_statement nodes.

#child_by_field

python
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

python
def _check_stdout(tree, filepath, config)

Detect print(), sys.stdout/stderr.write(), and logging.* calls.

#_check_entry_points

python
def _check_entry_points(project_path, config)

Check pyproject.toml for CLI entry point declarations.

#_always_terminates

python
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

python
def _terminator_label(node)

Return a human-readable label for the terminating construct.

#_check_unreachable_code

python
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

python
def lint(self, project_path: str, config: LanguageLintConfig) -> list[LintResult]

#scan_imports

python
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.