Core API

The core API provides the building blocks for writing rules and using the linter.

Rules

The Rule and LineRule base classes are the foundation for all lint rules. See the Writing custom rules guide for usage examples.

Base Rule class for Rude linter.

Simple API for rule authors with support for node filtering, configuration, and metadata dependencies.

class rude.core.rule.LineRule[source]

Bases: RuleBase, ABC

Base class for line-based rules.

More efficient than AST rules for pattern matching on raw text. The linter iterates lines once and calls all LineRules, avoiding redundant iteration.

Example:

class NoTodoComments(LineRule):
    code = "TODO001"
    message = "TODO comment found"

    def check_line(self, line: str, lineno: int, ctx: FileContext) -> Iterator[Diagnostic]:
        if "TODO" in line:
            col = line.index("TODO")
            yield self.diagnostic_at(lineno, col)
uses_line_infos: ClassVar[bool] = False

If True, check_line_info is used when pre-computed line metadata is available (from Rust), avoiding per-line decode and regex.

abstractmethod check_line(line, lineno, ctx, *, comment_pos=-1)[source]

Check a single line and yield diagnostics.

Parameters:
  • line (str) – The line content (decoded string, no trailing newline)

  • lineno (int) – Line number (1-based)

  • ctx (FileContext) – File context for accessing file-level info

  • comment_pos (int) – Position of ‘#’ comment start (-1 if none). Pre-computed by linter, ignores ‘#’ inside strings. Use line[:comment_pos] to get code portion.

Yields:

Diagnostic objects for any issues found

Return type:

Iterator[Diagnostic]

check_line_info(lineno, info, ctx)[source]

Fast path using pre-computed line metadata from Rust.

Override this when uses_line_infos = True. The info argument is a LineInfo struct (frozen pyclass) with named fields:

info.leading_spaces     (int)
info.indent_len         (int)
info.line_len           (int)
info.trailing_ws        (int)
info.comment_start      (int, -1 if no comment)
info.indent_has_tab     (bool)
info.indent_has_space   (bool)
info.is_blank           (bool)
info.is_in_string       (bool)
info.spaces_before_comment (int, -1 for block comment)
info.char_after_hash    (int, ASCII byte or 0)
info.leading_hashes     (int)
info.style_flags        (int, bitfield)

style_flags is a u8 bitfield with optimization hints:

bit 0 (0x01): DOUBLE_SPACE_AROUND_OP  -- 2+ spaces near operator
bit 1 (0x02): TAB_AROUND_OP           -- tab near operator
bit 2 (0x04): DOUBLE_SPACE_AFTER_COMMA -- 2+ spaces after , or ;
bit 3 (0x08): TAB_AFTER_COMMA         -- tab after , or ;
bit 4 (0x10): DOUBLE_SPACE_AROUND_KW  -- 2+ spaces near keyword
bit 5 (0x20): TAB_AROUND_KW           -- tab near keyword

Flags are hints: false positives OK, false negatives not allowed.

Parameters:
Return type:

Iterator[Diagnostic]

class rude.core.rule.Rule[source]

Bases: RuleBase, ABC

Base class for linting rules.

Example:

class NoEval(Rule):
    code = "S001"
    message = "eval() is a security risk"
    node_types = {NodeType.CALL}

    def check(self, node: Node) -> Iterator[Diagnostic]:
        if node.function_name == "eval":
            yield self.diagnostic(node)
node_types: ClassVar[set[NodeType] | None] = None

Tree-sitter node types to match. None = all nodes (discouraged).

metadata_dependencies: ClassVar[set[type]] = {}

Required metadata providers.

abstractmethod check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

diagnostic(node, message=None, *, fix=None, severity=None)[source]

Create a diagnostic for this rule.

Parameters:
Return type:

Diagnostic

Types

Core data types used throughout the API, including Diagnostic, FileContext, and Fix.

Core types for Rude linter.

Defines fundamental data structures: locations, edits, fixes, diagnostics, and file context with metadata provider support.

class rude.core.types.Diagnostic[source]

Bases: object

A linting diagnostic (error, warning, etc.).

Parameters:
__init__(code, message, location, severity=Severity.WARNING, fix=None)
Parameters:
Return type:

None

class rude.core.types.Edit[source]

Bases: object

A single text edit operation (byte-based).

Parameters:
  • start_byte (int)

  • end_byte (int)

  • new_text (str)

__init__(start_byte, end_byte, new_text)
Parameters:
  • start_byte (int)

  • end_byte (int)

  • new_text (str)

Return type:

None

class rude.core.types.FileContext[source]

Bases: object

Context for linting a single file.

Provides access to source, parsed tree, and metadata providers.

Parameters:
property text_lines: list[str]

Decoded text lines (no trailing newline). Cached.

property string_lines: frozenset[int]

Line numbers (1-based) inside multi-line strings. Cached.

classmethod from_analysis(path, source, tree, *, string_lines=None, noqa_map=None, line_infos=None)[source]

Create a FileContext with pre-computed analysis results.

Parameters:
Return type:

FileContext

line_start_byte(lineno)[source]

Byte offset of the start of the given 1-based line.

Parameters:

lineno (int)

Return type:

int

has_noqa(line, code=None)[source]

Check if line has a noqa comment suppressing this diagnostic.

Parameters:
Return type:

bool

get_metadata(provider_cls)[source]

Get metadata from a provider (lazy computed and cached).

Parameters:

provider_cls (type[TypeVar(MetadataProviderT, bound= MetadataProvider)])

Return type:

TypeVar(MetadataProviderT, bound= MetadataProvider)

set_metadata(provider_cls, value)[source]

Inject a pre-computed metadata provider into the cache.

Parameters:
Return type:

None

__init__(path, source, tree, _lines=None, _text=None, _text_lines=None, _string_lines=None, _noqa_map=None, _line_infos=None, _metadata_cache=<factory>)
Parameters:
Return type:

None

class rude.core.types.Fix[source]

Bases: object

Autofix for a diagnostic.

Fixes are declarative - rules describe WHAT should change, the linter handles HOW (including import insertion).

Parameters:
classmethod replace(node, new_text, *, description=None, imports=None, imports_from=None)[source]

Replace a node with new text.

Parameters:
Return type:

Fix

classmethod delete(node, *, description=None)[source]

Delete a node.

Parameters:
Return type:

Fix

classmethod insert_before(node, text, *, description=None, imports=None)[source]

Insert text before a node.

Parameters:
Return type:

Fix

classmethod insert_after(node, text, *, description=None, imports=None)[source]

Insert text after a node.

Parameters:
Return type:

Fix

classmethod add_decorator(node, decorator, *, description=None, imports=None)[source]

Add a decorator to a function or class.

Parameters:
Return type:

Fix

__init__(description, edits=(), imports_needed=(), imports_from_needed=())
Parameters:
Return type:

None

class rude.core.types.FixResult[source]

Bases: object

Result of applying fixes to source.

Parameters:
__init__(source, applied, dropped)
Parameters:
Return type:

None

class rude.core.types.Location[source]

Bases: object

Source code location (LSP compatible: line 1-indexed, column 0-indexed).

Parameters:
__init__(line, column, end_line=None, end_column=None)
Parameters:
Return type:

None

class rude.core.types.MetadataProvider[source]

Bases: Protocol

Protocol for metadata providers (ParentProvider, ScopeProvider, etc.).

Each provider computes additional analysis from a FileContext and returns itself with the results cached.

__init__(*args, **kwargs)
class rude.core.types.Severity[source]

Bases: Enum

Diagnostic severity levels.

Node

The Node wrapper around tree-sitter nodes, providing a Pythonic API for AST navigation and inspection. See the Writing custom rules guide for a quick reference table of all Node properties and methods.

Ergonomic wrapper around tree-sitter nodes.

Provides a Pythonic API for rule authors with cached properties and semantic helpers for Python constructs.

class rude.core.node.Node[source]

Bases: _NodeTypeMixin

Ergonomic wrapper around tree-sitter nodes.

Example:

if node.is_call and node.function_name == "eval":
    yield self.diagnostic(node)
Parameters:
__init__(node, ctx)[source]
Parameters:
Return type:

None

property is_missing: bool

True if the parser inserted this node to recover from a syntax error.

property parent_type: str | None

Parent node type (matches NodeProxy lightweight property).

property named_child_count: int

Number of named children (matches NodeProxy lightweight property).

property children: list[Node]

All child nodes (cached).

property named_children: list[Node]

Named child nodes only (cached).

walk()[source]

Depth-first traversal of all descendants using TreeCursor.

Uses tree-sitter’s TreeCursor for efficient navigation without allocating Node wrappers for unvisited children. This reduces memory allocations significantly for large ASTs.

Return type:

Iterator[Node]

find(node_type)[source]

Find all descendants of a given type.

Parameters:

node_type (str)

Return type:

Iterator[Node]

find_first(node_type)[source]

Find first descendant of a given type.

Parameters:

node_type (str)

Return type:

Node | None

find_where(predicate)[source]

Find all descendants matching a predicate.

Parameters:

predicate (Callable[[Node], bool])

Return type:

Iterator[Node]

ancestor(node_type)[source]

Find nearest ancestor of a given type.

Parameters:

node_type (str)

Return type:

Node | None

property function_name: str | None

foo() -> ‘foo’, bar.baz() -> ‘baz’

Type:

Simple function name

property full_call_name: str | None

os.path.join() -> ‘os.path.join’

Type:

Full dotted name

property call_arguments: list[Node]

Arguments of a call node.

property name: str | None

Name for function, class, or simple assignment.

property decorators: list[Node]

Decorators on function/class.

property decorator_names: list[str]

Decorator names as strings.

property parameters: list[Node]

Function parameters.

property body: Node | None

Body block for function/class/if/for/while.

property bases: list[Node]

Base classes for class definition.

property base_names: list[str]

Base class names as strings.

property import_module: str | None

Module being imported.

get_metadata(provider_cls)[source]

Shortcut for ctx.get_metadata().

Parameters:

provider_cls (type[TypeVar(MetadataProviderT, bound= MetadataProvider)])

Return type:

TypeVar(MetadataProviderT, bound= MetadataProvider)

property raw: TSNode

Underlying tree-sitter node.

class rude.core.node.NodeLike[source]

Bases: Protocol

Protocol documenting the shared Node/NodeProxy interface.

Both Node (full tree-sitter wrapper) and NodeProxy (lightweight batch proxy) satisfy this protocol. Rule authors can type-hint NodeLike when they need to accept either transparently.

__init__(*args, **kwargs)
class rude.core.node.NodeProxy[source]

Bases: _NodeTypeMixin

Lightweight proxy that duck-types Node for batch dispatch.

Wraps a frozen NodeEntry struct from Rust (3 slots vs 14), exposing fields as properties. Heavy properties (children, parent, etc.) inflate to a full Node on first access – O(log depth).

Parameters:
__init__(node_type, entry, ctx)[source]
Parameters:
Return type:

None

Node Types

Named constants for tree-sitter node types, used in rule node_types sets for IDE autocomplete and typo prevention.

rude.core.node_types.VALID_NODE_TYPES: frozenset[NodeType] = frozenset({NodeType.ALIASED_IMPORT, NodeType.ARGUMENT_LIST, NodeType.AS_PATTERN, NodeType.AS_PATTERN_TARGET, NodeType.ASSERT_STATEMENT, NodeType.ASSIGNMENT, NodeType.ATTRIBUTE, NodeType.AUGMENTED_ASSIGNMENT, NodeType.AWAIT, NodeType.BINARY_OPERATOR, NodeType.BLOCK, NodeType.BOOLEAN_OPERATOR, NodeType.BREAK_STATEMENT, NodeType.CALL, NodeType.CASE_CLAUSE, NodeType.CASE_PATTERN, NodeType.CHEVRON, NodeType.CLASS_DEFINITION, NodeType.CLASS_PATTERN, NodeType.COMMENT, NodeType.COMPARISON_OPERATOR, NodeType.COMPLEX_PATTERN, NodeType.CONCATENATED_STRING, NodeType.CONDITIONAL_EXPRESSION, NodeType.CONSTRAINED_TYPE, NodeType.CONTINUE_STATEMENT, NodeType.DECORATED_DEFINITION, NodeType.DECORATOR, NodeType.DEFAULT_PARAMETER, NodeType.DELETE_STATEMENT, NodeType.DICT_PATTERN, NodeType.DICTIONARY, NodeType.DICTIONARY_COMPREHENSION, NodeType.DICTIONARY_SPLAT, NodeType.DICTIONARY_SPLAT_PATTERN, NodeType.DOTTED_NAME, NodeType.ELIF_CLAUSE, NodeType.ELLIPSIS, NodeType.ELSE_CLAUSE, NodeType.ESCAPE_INTERPOLATION, NodeType.ESCAPE_SEQUENCE, NodeType.EXCEPT_CLAUSE, NodeType.EXEC_STATEMENT, NodeType.EXPRESSION_LIST, NodeType.EXPRESSION_STATEMENT, NodeType.FALSE, NodeType.FINALLY_CLAUSE, NodeType.FLOAT, NodeType.FOR_IN_CLAUSE, NodeType.FOR_STATEMENT, NodeType.FORMAT_EXPRESSION, NodeType.FORMAT_SPECIFIER, NodeType.FUNCTION_DEFINITION, NodeType.FUTURE_IMPORT_STATEMENT, NodeType.GENERATOR_EXPRESSION, NodeType.GENERIC_TYPE, NodeType.GLOBAL_STATEMENT, NodeType.IDENTIFIER, NodeType.IF_CLAUSE, NodeType.IF_STATEMENT, NodeType.IMPORT_FROM_STATEMENT, NodeType.IMPORT_PREFIX, NodeType.IMPORT_STATEMENT, NodeType.INTEGER, NodeType.INTERPOLATION, NodeType.KEYWORD_ARGUMENT, NodeType.KEYWORD_PATTERN, NodeType.KEYWORD_SEPARATOR, NodeType.LAMBDA, NodeType.LAMBDA_PARAMETERS, NodeType.LINE_CONTINUATION, NodeType.LIST, NodeType.LIST_COMPREHENSION, NodeType.LIST_PATTERN, NodeType.LIST_SPLAT, NodeType.LIST_SPLAT_PATTERN, NodeType.MATCH_STATEMENT, NodeType.MEMBER_TYPE, NodeType.MODULE, NodeType.NAMED_EXPRESSION, NodeType.NONE, NodeType.NONLOCAL_STATEMENT, NodeType.NOT_OPERATOR, NodeType.PAIR, NodeType.PARAMETERS, NodeType.PARENTHESIZED_EXPRESSION, NodeType.PARENTHESIZED_LIST_SPLAT, NodeType.PASS_STATEMENT, NodeType.PATTERN_LIST, NodeType.POSITIONAL_SEPARATOR, NodeType.PRINT_STATEMENT, NodeType.RAISE_STATEMENT, NodeType.RELATIVE_IMPORT, NodeType.RETURN_STATEMENT, NodeType.SET, NodeType.SET_COMPREHENSION, NodeType.SLICE, NodeType.SPLAT_PATTERN, NodeType.SPLAT_TYPE, NodeType.STRING, NodeType.STRING_CONTENT, NodeType.STRING_END, NodeType.STRING_START, NodeType.SUBSCRIPT, NodeType.TRUE, NodeType.TRY_STATEMENT, NodeType.TUPLE, NodeType.TUPLE_PATTERN, NodeType.TYPE, NodeType.TYPE_ALIAS_STATEMENT, NodeType.TYPE_CONVERSION, NodeType.TYPE_PARAMETER, NodeType.TYPED_DEFAULT_PARAMETER, NodeType.TYPED_PARAMETER, NodeType.UNARY_OPERATOR, NodeType.UNION_PATTERN, NodeType.UNION_TYPE, NodeType.WHILE_STATEMENT, NodeType.WILDCARD_IMPORT, NodeType.WITH_CLAUSE, NodeType.WITH_ITEM, NodeType.WITH_STATEMENT, NodeType.YIELD})

All named node types from tree-sitter-python’s grammar.

class rude.core.node_types.NodeType[source]

Bases: StrEnum

Tree-sitter node type constants.

Used in Rule.node_types for autocomplete and validation:

from rude import Rule, NodeType

class MyRule(Rule):
    node_types = {NodeType.CALL}
__new__(value)

Linter

The Linter class is the main entry point for running rules programmatically. See the Quickstart for CLI usage and Plugin development for testing rules.

Linter engine - orchestrates rules, file processing, and autofixes.

Default (–jobs=1): single process with Rust rayon parallelism (all CPUs, low memory). With –jobs=N (N>1): N subprocesses for parallel Python rules (higher memory).

class rude.core.linter.CheckOptions[source]

Bases: object

Options for parallel checking.

Parameters:
__init__(workers=None, fail_fast=False, max_errors=None, fail_on_warning=False, timeout_per_file=30.0)
Parameters:
Return type:

None

class rude.core.linter.Linter[source]

Bases: object

Main linter engine.

Example:

linter = Linter()
linter.register(NoEval())

for diag in linter.check_file("src/main.py"):
    print(diag)

# With autofix
diagnostics, result = linter.fix_file("src/main.py")
if result:
    Path("src/main.py").write_text(result.source)
Parameters:

debug (bool)

__init__(*, debug=False)[source]
Parameters:

debug (bool)

Return type:

None

fix_file(path)[source]

Lint and fix a file. Returns (diagnostics, FixResult or None).

Parameters:

path (Path | str)

Return type:

tuple[list[Diagnostic], FixResult | None]

fix_source(source, filename='<string>')[source]

Lint and fix source code.

Parameters:
Return type:

tuple[list[Diagnostic], FixResult | None]

fix_file_in_place(path)[source]

Fix file and write back.

Parameters:

path (Path | str)

Return type:

tuple[list[Diagnostic], FixResult | None]

check_paths_parallel(paths, options=None, *, already_resolved=False)[source]

Lint paths with parallel execution.

Default (workers=None or 1): Rust rayon in a single Python process. workers > 1: N subprocesses, each running Rust rayon + Python rules.

Parameters:
  • paths (Sequence[Path | str]) – Files or directories to check

  • options (CheckOptions | None) – Check options (workers, fail_fast, max_errors, etc.)

  • already_resolved (bool) – If True, skip resolve_paths (paths are already .py files)

Yields:

(path, diagnostic) tuples

Return type:

Iterator[tuple[Path, Diagnostic]]

Configuration

Handles pyproject.toml parsing and rule selection. See the Configuration guide for user-facing documentation.

Configuration from pyproject.toml.

class rude.core.config.Config[source]

Rude configuration from [tool.rude].

Parameters:
resolve_path(path)[source]

Resolve a local-rules path relative to the config file.

Raises ValueError if the resolved path escapes the project root.

Parameters:

path (str)

Return type:

Path

__init__(select=<factory>, ignore=<factory>, plugins=<factory>, local_rules=<factory>, rule_options=<factory>, config_path=None)
Parameters:
Return type:

None

rude.core.config.find_config_file(start=None)[source]

Find pyproject.toml with [tool.rude] section.

Parameters:

start (Path | None)

Return type:

Path | None

rude.core.config.load_config(path=None)[source]

Load config from pyproject.toml.

Parameters:

path (Path | str | None)

Return type:

Config

Parser

Tree-sitter parser interface for parsing Python source into syntax trees.

Tree-sitter parser for Python.

rude.core.parser.parse(source)[source]

Parse Python source bytes into a tree-sitter tree.

Parameters:

source (bytes)

Return type:

TSTree

rude.core.parser.parse_file(path)[source]

Parse a Python file and return a FileContext.

Parameters:

path (Path | str)

Return type:

FileContext

rude.core.parser.parse_string(source)[source]

Parse a Python source string into a tree-sitter tree.

Parameters:

source (str)

Return type:

TSTree

Rule Discovery

Discovers and loads rules from entry points, local files, and plugins. See Plugin development for the plugin loading mechanism.

Rule discovery from built-in, plugins, and local sources.

class rude.core.rule_discovery.RuleDiscovery[source]

Discovers rules from all configured sources.

discover_all(*, select=None, ignore=None, plugins=None, local_rules=None, load_entry_points=True)[source]

Discover and instantiate all rules.

Parameters:
Return type:

list[RuleBase]

File Finder

Discovers Python files with .gitignore support and automatic directory skipping. See Configuration for the file filtering documentation.

File discovery with gitignore support using fast os.scandir.

rude.core.file_finder.find_python_files(root, *, respect_gitignore=True)[source]

Find all Python files under root directory.

Parameters:
Return type:

Iterator[Path]

rude.core.file_finder.resolve_paths(paths)[source]

Resolve paths (files or directories) to Python files.

Parameters:

paths (Sequence[str | Path])

Return type:

Iterator[Path]