Built-in Rules API

Auto-generated API reference for built-in rule implementations.

Pyflakes

Pyflakes-style rules ported to Rude.

F401: Module imported but unused F541: f-string without any placeholders F542: t-string without any placeholders F601: Dictionary key literal repeated F602: Dictionary key variable repeated F621: Too many expressions in star-unpacking F622: Two starred expressions in assignment F631: Assert test is non-empty tuple F632: Use of is/is not with literal F634: If test is non-empty tuple F701: break outside loop F702: continue outside loop F704: yield outside function F706: return outside function F707: default except not last F824: global/nonlocal declared but never assigned F831: Duplicate argument in function definition F841: Local variable assigned but never used F901: raise NotImplemented (should be NotImplementedError)

These rules use tree-sitter for AST analysis and ScopeProvider for accurate scope tracking.

class rude.rules.pyflakes.AssertTuple[source]

Bases: Rule

F631: Assert test is a non-empty tuple, which is always True.

Rationale: A tuple like (x, y) is always truthy, so the assertion never fails. This is usually a misplaced comma.

Example:

# Bad
assert (x, y)  # F631 - tuple is always truthy

# Good
assert x and y
code: ClassVar[str] = 'F631'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'assertion test is a non-empty tuple, which is always True'

Default diagnostic message.

severity: ClassVar[Severity] = 'warning'

Default severity. None = ERROR.

node_types: ClassVar[set[NodeType] | None] = {NodeType.ASSERT_STATEMENT}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pyflakes.BreakOutsideLoop[source]

Bases: Rule

F701: break not properly in loop.

Rationale: break outside a loop is a SyntaxError.

Example:

# Bad
break  # F701 - not inside a loop

# Good
while True:
    break
code: ClassVar[str] = 'F701'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = "'break' not properly in loop"

Default diagnostic message.

severity: ClassVar[Severity] = 'error'

Default severity. None = ERROR.

node_types: ClassVar[set[NodeType] | None] = {NodeType.BREAK_STATEMENT}

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

metadata_dependencies: ClassVar[set[type]] = {<class 'rude.providers.ScopeProvider'>}

Required metadata providers.

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pyflakes.ContinueOutsideLoop[source]

Bases: Rule

F702: continue not properly in loop.

Rationale: continue outside a loop is a SyntaxError.

Example:

# Bad
continue  # F702 - not inside a loop

# Good
for i in range(10):
    continue
code: ClassVar[str] = 'F702'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = "'continue' not properly in loop"

Default diagnostic message.

severity: ClassVar[Severity] = 'error'

Default severity. None = ERROR.

node_types: ClassVar[set[NodeType] | None] = {NodeType.CONTINUE_STATEMENT}

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

metadata_dependencies: ClassVar[set[type]] = {<class 'rude.providers.ScopeProvider'>}

Required metadata providers.

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pyflakes.DefaultExceptNotLast[source]

Bases: Rule

F707: A bare except: clause must be the last exception handler.

Rationale: A bare except: before a typed handler is a SyntaxError because the typed handler would be unreachable.

Example:

# Bad
try:
    pass
except:        # F707 - bare except must be last
    pass
except TypeError:
    pass

# Good
try:
    pass
except TypeError:
    pass
except:
    pass
code: ClassVar[str] = 'F707'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'an except clause without an exception type must be last'

Default diagnostic message.

severity: ClassVar[Severity] = 'error'

Default severity. None = ERROR.

node_types: ClassVar[set[NodeType] | None] = {NodeType.TRY_STATEMENT}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pyflakes.DoctestSyntaxError[source]

Bases: Rule

F721: Syntax error in doctest.

Rationale: Doctest examples with invalid syntax will fail when run, and may indicate stale or incorrect documentation.

Example:

# Bad
def foo():
    '''
    >>> x = [1, 2, 3
    '''  # F721 - unclosed bracket in doctest
    pass

# Good
def foo():
    '''
    >>> x = [1, 2, 3]
    '''
    pass
code: ClassVar[str] = 'F721'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'syntax error in doctest'

Default diagnostic message.

severity: ClassVar[Severity] = 'error'

Default severity. None = ERROR.

node_types: ClassVar[set[NodeType] | None] = {NodeType.STRING}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pyflakes.DuplicateArgument[source]

Bases: Rule

F831: Duplicate argument in function definition.

Rationale: Duplicate parameter names cause a SyntaxError in Python 3.

Example:

# Bad
def foo(a, a):  # F831 - duplicate argument 'a'
    pass

# Good
def foo(a, b):
    pass
code: ClassVar[str] = 'F831'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = "duplicate argument '{name}' in function definition"

Default diagnostic message.

severity: ClassVar[Severity] = 'error'

Default severity. None = ERROR.

node_types: ClassVar[set[NodeType] | None] = {NodeType.FUNCTION_DEFINITION, NodeType.LAMBDA}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pyflakes.FStringMissingPlaceholders[source]

Bases: _PrefixStringMissingPlaceholders

F541: f-string without any placeholders.

An f-string without placeholders is probably a mistake - the f prefix should be removed.

Example:

x = f"hello"       # F541 - no placeholders
x = f"hello {x}"   # OK - has placeholder
x = "hello"        # OK - regular string
code: ClassVar[str] = 'F541'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'f-string without any placeholders'

Default diagnostic message.

class rude.rules.pyflakes.ForwardAnnotationSyntaxError[source]

Bases: Rule

F722: Syntax error in forward annotation.

Rationale: A forward annotation with invalid syntax will raise a SyntaxError when evaluated at runtime or by type checkers.

Example:

# Bad
x: "List[int"  # F722 - unclosed bracket

# Good
x: "List[int]"
code: ClassVar[str] = 'F722'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'syntax error in forward annotation {annotation!r}'

Default diagnostic message.

severity: ClassVar[Severity] = 'error'

Default severity. None = ERROR.

node_types: ClassVar[set[NodeType] | None] = {NodeType.STRING}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pyflakes.FutureFeatureNotDefined[source]

Bases: Rule

F407: Undefined name in __future__ import.

Example:

from __future__ import nonexistent_feature  # F407
from __future__ import annotations  # OK
code: ClassVar[str] = 'F407'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = "future feature '{name}' is not defined"

Default diagnostic message.

severity: ClassVar[Severity] = 'error'

Default severity. None = ERROR.

node_types: ClassVar[set[NodeType] | None] = {NodeType.FUTURE_IMPORT_STATEMENT, NodeType.IMPORT_FROM_STATEMENT}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pyflakes.IfTuple[source]

Bases: Rule

F634: If test is a non-empty tuple, which is always True.

Rationale: A non-empty tuple is always truthy, so the branch always executes. This is usually a misplaced comma.

Example:

# Bad
if (x, y):  # F634 - tuple is always truthy
    pass

# Good
if x and y:
    pass
code: ClassVar[str] = 'F634'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'if test is a non-empty tuple, which is always True'

Default diagnostic message.

severity: ClassVar[Severity] = 'warning'

Default severity. None = ERROR.

node_types: ClassVar[set[NodeType] | None] = {NodeType.IF_STATEMENT}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pyflakes.ImportShadowedByLoopVar[source]

Bases: Rule

F402: Import shadowed by loop variable.

Rationale: Reusing an imported name as a loop variable makes the import inaccessible after the loop, which is usually unintentional.

Example:

# Bad
from os import path

for path in paths:  # F402 - shadows import
    print(path)

# Good
from os import path

for p in paths:
    print(p)

Optimized: Uses pre-computed shadowed_imports from Rust SemanticModel.

code: ClassVar[str] = 'F402'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = "import '{name}' from line {line} shadowed by loop variable"

Default diagnostic message.

severity: ClassVar[Severity] = 'warning'

Default severity. None = ERROR.

node_types: ClassVar[set[NodeType] | None] = {NodeType.MODULE}

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

metadata_dependencies: ClassVar[set[type]] = {<class 'rude.providers.ScopeProvider'>}

Required metadata providers.

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pyflakes.ImportStarNotPermitted[source]

Bases: Rule

F406: Star import (from X import *) used outside module level.

Star imports are only allowed at the module level, not inside functions or classes.

Example:

from os import *  # OK - at module level

def foo():
    from os import *  # F406 - not at module level
code: ClassVar[str] = 'F406'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = "'from {module} import *' only allowed at module level"

Default diagnostic message.

severity: ClassVar[Severity] = 'error'

Default severity. None = ERROR.

node_types: ClassVar[set[NodeType] | None] = {NodeType.IMPORT_FROM_STATEMENT}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pyflakes.ImportStarUsed[source]

Bases: Rule

F403: from X import * used; unable to detect undefined names.

Rationale: Star imports make it impossible to statically determine what names are defined, which can hide errors and cause name collisions.

Example:

# Bad
from os import *  # F403 - star import used

# Good
from os import path, getcwd
code: ClassVar[str] = 'F403'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = "'from {module} import *' used; unable to detect undefined names"

Default diagnostic message.

severity: ClassVar[Severity] = 'warning'

Default severity. None = ERROR.

node_types: ClassVar[set[NodeType] | None] = {NodeType.IMPORT_FROM_STATEMENT}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pyflakes.InvalidPrintSyntax[source]

Bases: Rule

F633: Use of >> is invalid with print function.

In Python 2, print >> file, data was used to redirect print output. This syntax is invalid in Python 3.

Example:

print >> sys.stderr, "error"  # F633 - invalid syntax
print("error", file=sys.stderr)  # OK - Python 3 syntax
code: ClassVar[str] = 'F633'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'use of >> is invalid with print function'

Default diagnostic message.

severity: ClassVar[Severity] = 'error'

Default severity. None = ERROR.

node_types: ClassVar[set[NodeType] | None] = {NodeType.PRINT_STATEMENT}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pyflakes.IsLiteral[source]

Bases: Rule

F632: Use of is or is not with a literal.

Using is with literals can have surprising behavior due to Python’s interning. Use == instead.

Example:

x is 1        # F632 - use `==` instead
x is "foo"    # F632
x is None     # OK - None is a singleton
x is True     # OK - True/False are singletons
code: ClassVar[str] = 'F632'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = "use ==/!= to compare '{literal}', not is/is not"

Default diagnostic message.

severity: ClassVar[Severity] = 'warning'

Default severity. None = ERROR.

node_types: ClassVar[set[NodeType] | None] = {NodeType.COMPARISON_OPERATOR}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pyflakes.LateFutureImport[source]

Bases: Rule

F404: from __future__ import not at the beginning of the file.

Future imports must appear at the beginning of the file, after any module docstrings or comments, but before any other code.

Example:

x = 1
from __future__ import annotations  # F404 - too late!

from __future__ import annotations
x = 1  # OK
code: ClassVar[str] = 'F404'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'from __future__ imports must occur at the beginning of the file'

Default diagnostic message.

severity: ClassVar[Severity] = 'error'

Default severity. None = ERROR.

node_types: ClassVar[set[NodeType] | None] = {NodeType.IMPORT_FROM_STATEMENT}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pyflakes.MultiValueRepeatedKeyLiteral[source]

Bases: Rule

F601: Dictionary literal contains repeated key (literal).

Pyflakes reports ALL occurrences of a key when: - The key appears more than once - The values are different

Example:

{"a": 1, "a": 2}  # F601 - both "a" keys reported
{"a": 1, "a": 1}  # OK - same value, no report
code: ClassVar[str] = 'F601'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'dictionary key {key!r} repeated'

Default diagnostic message.

severity: ClassVar[Severity] = 'warning'

Default severity. None = ERROR.

node_types: ClassVar[set[NodeType] | None] = {NodeType.DICTIONARY}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pyflakes.MultiValueRepeatedKeyVariable[source]

Bases: Rule

F602: Dictionary literal contains repeated key (variable).

Pyflakes reports ALL occurrences of a variable key when: - The variable key appears more than once - The values are different

Example:

x = "key"
{x: 1, x: 2}  # F602 - both x keys reported
{x: 1, x: 1}  # OK - same value, no report
code: ClassVar[str] = 'F602'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'dictionary key variable {key!r} repeated'

Default diagnostic message.

severity: ClassVar[Severity] = 'warning'

Default severity. None = ERROR.

node_types: ClassVar[set[NodeType] | None] = {NodeType.DICTIONARY}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pyflakes.PercentFormatExpectedMapping[source]

Bases: Rule

F502: % format expected mapping but got sequence.

Rationale: Named placeholders like %(name)s require a mapping (dict), not a sequence. This causes a TypeError at runtime.

Example:

# Bad
"%(name)s" % (1, 2)  # F502 - expected dict, got tuple

# Good
"%(name)s" % {"name": "Alice"}
code: ClassVar[str] = 'F502'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'percent format expected mapping but found sequence'

Default diagnostic message.

severity: ClassVar[Severity] = 'error'

Default severity. None = ERROR.

node_types: ClassVar[set[NodeType] | None] = {NodeType.BINARY_OPERATOR}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pyflakes.PercentFormatExpectedSequence[source]

Bases: Rule

F503: % format expected sequence but got mapping.

Rationale: Positional placeholders like %s require a sequence (tuple), not a mapping. This causes a TypeError at runtime.

Example:

# Bad
"%s %s" % {"a": 1}  # F503 - expected tuple, got dict

# Good
"%s %s" % (1, 2)
code: ClassVar[str] = 'F503'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'percent format expected sequence but found mapping'

Default diagnostic message.

severity: ClassVar[Severity] = 'error'

Default severity. None = ERROR.

node_types: ClassVar[set[NodeType] | None] = {NodeType.BINARY_OPERATOR}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pyflakes.PercentFormatExtraNamedArguments[source]

Bases: Rule

F504: % format has unused named arguments.

Rationale: Extra keys in the mapping are silently ignored, which usually indicates a bug in the format string.

Example:

# Bad
"%(name)s" % {"name": 1, "other": 2}  # F504 - other is unused

# Good
"%(name)s" % {"name": 1}
code: ClassVar[str] = 'F504'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'percent format has unused named argument(s): {names}'

Default diagnostic message.

severity: ClassVar[Severity] = 'warning'

Default severity. None = ERROR.

node_types: ClassVar[set[NodeType] | None] = {NodeType.BINARY_OPERATOR}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pyflakes.PercentFormatInvalidFormat[source]

Bases: Rule

F501: Invalid % format string.

Rationale: An invalid format specifier causes a ValueError at runtime.

Example:

# Bad
"%z" % x  # F501 - z is not a valid format character

# Good
"%s" % x
code: ClassVar[str] = 'F501'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'percent format has invalid format string: {error}'

Default diagnostic message.

severity: ClassVar[Severity] = 'error'

Default severity. None = ERROR.

node_types: ClassVar[set[NodeType] | None] = {NodeType.BINARY_OPERATOR}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pyflakes.PercentFormatMissingArgument[source]

Bases: Rule

F505: % format is missing named argument.

Rationale: A missing key causes a KeyError at runtime.

Example:

# Bad
"%(name)s %(other)s" % {"name": 1}  # F505 - missing 'other'

# Good
"%(name)s %(other)s" % {"name": 1, "other": 2}
code: ClassVar[str] = 'F505'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'percent format is missing argument(s): {missing}'

Default diagnostic message.

severity: ClassVar[Severity] = 'error'

Default severity. None = ERROR.

node_types: ClassVar[set[NodeType] | None] = {NodeType.BINARY_OPERATOR}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pyflakes.PercentFormatMixedPositionalAndNamed[source]

Bases: Rule

F506: % format mixes positional and named placeholders.

Rationale: Python does not support mixing positional and named placeholders in %-formatting. This causes a TypeError.

Example:

# Bad
"%s %(name)s" % (1, {"name": 2})  # F506 - can't mix

# Good
"%(first)s %(name)s" % {"first": 1, "name": 2}
code: ClassVar[str] = 'F506'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'percent format has mixed positional and named placeholders'

Default diagnostic message.

severity: ClassVar[Severity] = 'error'

Default severity. None = ERROR.

node_types: ClassVar[set[NodeType] | None] = {NodeType.BINARY_OPERATOR}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pyflakes.PercentFormatPositionalCountMismatch[source]

Bases: Rule

F507: % format positional argument count mismatch.

Rationale: Providing the wrong number of arguments causes a TypeError at runtime.

Example:

# Bad
"%s %s" % (1,)  # F507 - expected 2 arguments, got 1

# Good
"%s %s" % (1, 2)
code: ClassVar[str] = 'F507'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'percent format expected {expected} argument(s) but found {found}'

Default diagnostic message.

severity: ClassVar[Severity] = 'error'

Default severity. None = ERROR.

node_types: ClassVar[set[NodeType] | None] = {NodeType.BINARY_OPERATOR}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pyflakes.PercentFormatStarRequiresSequence[source]

Bases: Rule

F508: % format with * width/precision requires sequence.

Rationale: The * specifier reads width/precision from the argument tuple, so a mapping cannot be used.

Example:

# Bad
"%*s" % {"width": 5}  # F508 - * requires positional args

# Good
"%*s" % (10, "hello")
code: ClassVar[str] = 'F508'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'percent format with * width/precision requires sequence argument'

Default diagnostic message.

severity: ClassVar[Severity] = 'error'

Default severity. None = ERROR.

node_types: ClassVar[set[NodeType] | None] = {NodeType.BINARY_OPERATOR}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pyflakes.PercentFormatUnsupportedCharacter[source]

Bases: Rule

F509: % format has unsupported format character.

Rationale: Using an unsupported conversion character causes a ValueError at runtime.

Example:

# Bad
"%z" % x  # F509 - z is not a valid format character

# Good
"%s" % x
code: ClassVar[str] = 'F509'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = "percent format has unsupported format character '{char}'"

Default diagnostic message.

severity: ClassVar[Severity] = 'error'

Default severity. None = ERROR.

node_types: ClassVar[set[NodeType] | None] = {NodeType.BINARY_OPERATOR}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pyflakes.RaiseNotImplemented[source]

Bases: Rule

F901: raise NotImplemented should be raise NotImplementedError.

NotImplemented is a special value used for binary operations, not an exception.

Example:

raise NotImplemented           # F901 - wrong!
raise NotImplementedError()    # OK
raise NotImplementedError      # OK
code: ClassVar[str] = 'F901'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'raise NotImplemented should be raise NotImplementedError'

Default diagnostic message.

severity: ClassVar[Severity] = 'error'

Default severity. None = ERROR.

node_types: ClassVar[set[NodeType] | None] = {NodeType.RAISE_STATEMENT}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pyflakes.RedefinedWhileUnused[source]

Bases: Rule

F811: Redefinition of unused name from line N.

Rationale: Redefining a name before it is used usually indicates a copy-paste error or a redundant import.

Example:

# Bad
import os
import os  # F811 - redefinition of unused 'os' from line 1

# Good
import os

Optimized to use SemanticModel.redefinitions which tracks all binding redefinitions (assignment overwriting existing binding). Also uses model.bindings for import redefinitions.

code: ClassVar[str] = 'F811'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = "redefinition of unused '{name}' from line {line}"

Default diagnostic message.

severity: ClassVar[Severity] = 'warning'

Default severity. None = ERROR.

node_types: ClassVar[set[NodeType] | None] = {NodeType.MODULE}

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

metadata_dependencies: ClassVar[set[type]] = {<class 'rude.providers.ScopeProvider'>}

Required metadata providers.

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pyflakes.ReturnOutsideFunction[source]

Bases: Rule

F706: return statement outside of a function.

Rationale: A return at module level is a SyntaxError.

Example:

# Bad
return 1  # F706 - not inside a function

# Good
def foo():
    return 1
code: ClassVar[str] = 'F706'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = "'return' outside function"

Default diagnostic message.

severity: ClassVar[Severity] = 'error'

Default severity. None = ERROR.

node_types: ClassVar[set[NodeType] | None] = {NodeType.RETURN_STATEMENT}

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

metadata_dependencies: ClassVar[set[type]] = {<class 'rude.providers.ScopeProvider'>}

Required metadata providers.

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pyflakes.StringDotFormatExtraNamedArguments[source]

Bases: Rule

F522: .format() call has unused named arguments.

Rationale: Extra named arguments are silently ignored, which usually indicates a bug in the format string.

Example:

# Bad
"{name}".format(name=a, other=b)  # F522 - other is unused

# Good
"{name}".format(name=a)
code: ClassVar[str] = 'F522'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'format string has unused named argument(s): {names}'

Default diagnostic message.

severity: ClassVar[Severity] = 'warning'

Default severity. None = ERROR.

node_types: ClassVar[set[NodeType] | None] = {NodeType.CALL}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pyflakes.StringDotFormatExtraPositionalArguments[source]

Bases: Rule

F523: .format() call has unused positional arguments.

Rationale: Extra arguments are silently ignored, which usually indicates a bug in the format string.

Example:

# Bad
"{0}".format(a, b, c)  # F523 - b and c are unused

# Good
"{0} {1} {2}".format(a, b, c)
code: ClassVar[str] = 'F523'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'format string has {count} unused positional argument(s)'

Default diagnostic message.

severity: ClassVar[Severity] = 'warning'

Default severity. None = ERROR.

node_types: ClassVar[set[NodeType] | None] = {NodeType.CALL}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pyflakes.StringDotFormatInvalidFormat[source]

Bases: Rule

F521: Invalid .format() format string.

Rationale: An invalid format string causes a ValueError at runtime.

Example:

# Bad
"{".format()     # F521 - unclosed brace
"{0!z}".format() # F521 - unknown conversion

# Good
"{}".format(value)
code: ClassVar[str] = 'F521'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'format string has invalid format: {error}'

Default diagnostic message.

severity: ClassVar[Severity] = 'error'

Default severity. None = ERROR.

node_types: ClassVar[set[NodeType] | None] = {NodeType.CALL}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pyflakes.StringDotFormatMissingArgument[source]

Bases: Rule

F524: .format() call is missing arguments.

Rationale: Missing arguments cause a KeyError or IndexError at runtime.

Example:

# Bad
"{0} {1}".format(a)  # F524 - missing argument 1
"{name}".format()    # F524 - missing argument 'name'

# Good
"{0} {1}".format(a, b)
code: ClassVar[str] = 'F524'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'format string is missing argument(s): {missing}'

Default diagnostic message.

severity: ClassVar[Severity] = 'error'

Default severity. None = ERROR.

node_types: ClassVar[set[NodeType] | None] = {NodeType.CALL}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pyflakes.StringDotFormatMixingAutomatic[source]

Bases: Rule

F525: Mixing automatic and manual field numbering in .format().

Rationale: Python does not allow mixing automatic ({}) and manual ({0}) field numbering, raising a ValueError at runtime.

Example:

# Bad
"{} {0}".format(a, b)  # F525 - mixing auto and manual

# Good
"{} {}".format(a, b)   # all auto
"{0} {1}".format(a, b) # all manual
code: ClassVar[str] = 'F525'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'format string mixes automatic and manual field specification'

Default diagnostic message.

severity: ClassVar[Severity] = 'error'

Default severity. None = ERROR.

node_types: ClassVar[set[NodeType] | None] = {NodeType.CALL}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pyflakes.TStringMissingPlaceholders[source]

Bases: _PrefixStringMissingPlaceholders

F542: t-string without any placeholders.

Rationale: A t-string without placeholders adds overhead for no benefit. Remove the t prefix to use a regular string.

Example:

# Bad
x = t"hello"       # F542 - no placeholders

# Good
x = t"hello {name}"
x = "hello"        # plain string
code: ClassVar[str] = 'F542'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 't-string without any placeholders'

Default diagnostic message.

class rude.rules.pyflakes.TooManyExpressionsInStarredAssignment[source]

Bases: Rule

F621: Too many expressions in starred assignment target.

Rationale: Python limits unpacking targets to 255 elements. This is a compile-time error caught statically.

Example:

# Bad
a, *b, c, d, e, f, g, ... = items  # Too many targets

# Good
first, *rest = items
code: ClassVar[str] = 'F621'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'too many expressions in star-unpacking assignment'

Default diagnostic message.

severity: ClassVar[Severity] = 'error'

Default severity. None = ERROR.

node_types: ClassVar[set[NodeType] | None] = {NodeType.ASSIGNMENT}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pyflakes.TwoStarredExpressions[source]

Bases: Rule

F622: Two or more starred expressions in assignment.

Rationale: Python only allows one starred expression per assignment target. This is a SyntaxError.

Example:

# Bad
*a, *b = [1, 2, 3]  # F622 - two starred expressions

# Good
a, *b = [1, 2, 3]
code: ClassVar[str] = 'F622'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'two or more starred expressions in assignment'

Default diagnostic message.

severity: ClassVar[Severity] = 'error'

Default severity. None = ERROR.

node_types: ClassVar[set[NodeType] | None] = {NodeType.ASSIGNMENT}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pyflakes.UndefinedExport[source]

Bases: Rule

F822: Name in __all__ is not defined.

Rationale: Listing an undefined name in __all__ causes an AttributeError when the module is imported with *.

Example:

# Bad
__all__ = ["foo", "bar"]  # F822 - bar is not defined

def foo():
    pass

# Good
__all__ = ["foo"]

def foo():
    pass
code: ClassVar[str] = 'F822'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = "undefined name '{name}' in __all__"

Default diagnostic message.

severity: ClassVar[Severity] = 'error'

Default severity. None = ERROR.

node_types: ClassVar[set[NodeType] | None] = {NodeType.ASSIGNMENT}

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

metadata_dependencies: ClassVar[set[type]] = {<class 'rude.providers.ScopeProvider'>}

Required metadata providers.

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pyflakes.UndefinedLocal[source]

Bases: Rule

F823: Local variable referenced before assignment.

Rationale: Using a local variable before it is assigned causes an UnboundLocalError at runtime.

Example:

# Bad
def foo():
    print(x)  # F823 - x used before assignment
    x = 1

# Good
def foo():
    x = 1
    print(x)

Optimized: Uses pre-computed undefined_locals from Rust SemanticModel.

code: ClassVar[str] = 'F823'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = "local variable '{name}' referenced before assignment"

Default diagnostic message.

severity: ClassVar[Severity] = 'error'

Default severity. None = ERROR.

node_types: ClassVar[set[NodeType] | None] = {NodeType.MODULE}

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

metadata_dependencies: ClassVar[set[type]] = {<class 'rude.providers.ScopeProvider'>}

Required metadata providers.

check(node)[source]

Check for uses before definitions using pre-computed list from Rust.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pyflakes.UndefinedName[source]

Bases: Rule

F821: Name is not defined.

Rationale: Using an undefined name causes a NameError at runtime.

Example:

# Bad
print(undefined_variable)  # F821

# Good
x = 1
print(x)

Optimized to use pre-computed unresolved names from ScopeProvider.

code: ClassVar[str] = 'F821'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = "undefined name '{name}'"

Default diagnostic message.

severity: ClassVar[Severity] = 'error'

Default severity. None = ERROR.

node_types: ClassVar[set[NodeType] | None] = {NodeType.MODULE}

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

metadata_dependencies: ClassVar[set[type]] = {<class 'rude.providers.ScopeProvider'>}

Required metadata providers.

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pyflakes.UnusedAnnotation[source]

Bases: Rule

F842: Variable is annotated but never used or assigned a value.

Rationale: An annotation without an assignment or use is dead code that should be removed or completed.

Example:

# Bad
def foo():
    x: int       # F842 - x is never used or assigned

# Good
def foo():
    x: int = 1

Optimized: Uses pre-computed unused_annotations from Rust SemanticModel.

code: ClassVar[str] = 'F842'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = "local variable '{name}' is annotated but never used"

Default diagnostic message.

severity: ClassVar[Severity] = 'warning'

Default severity. None = ERROR.

node_types: ClassVar[set[NodeType] | None] = {NodeType.MODULE}

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

metadata_dependencies: ClassVar[set[type]] = {<class 'rude.providers.ScopeProvider'>}

Required metadata providers.

check(node)[source]

Find annotations without assignments using pre-computed list from Rust.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pyflakes.UnusedImport[source]

Bases: Rule

F401: Module imported but unused.

Example:

import os      # F401 - os is never used
import sys
print(sys.version)

Optimized: Uses pre-computed unused_imports from Rust SemanticModel.

code: ClassVar[str] = 'F401'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = "'{name}' imported but unused"

Default diagnostic message.

severity: ClassVar[Severity] = 'warning'

Default severity. None = ERROR.

node_types: ClassVar[set[NodeType] | None] = {NodeType.MODULE}

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

metadata_dependencies: ClassVar[set[type]] = {<class 'rude.providers.ScopeProvider'>}

Required metadata providers.

check(node)[source]

Check for unused imports using pre-computed list from Rust.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pyflakes.UnusedIndirectAssignment[source]

Bases: Rule

F824: Global or nonlocal declaration but name is never assigned in this scope.

Rationale: A global or nonlocal declaration without a subsequent assignment is unnecessary and misleading.

Example:

# Bad
def foo():
    global x   # F824 - x is never assigned in foo()
    print(x)

# Good
def foo():
    print(x)   # just read the global directly

Optimized: Uses pre-computed unused_declarations from Rust SemanticModel.

code: ClassVar[str] = 'F824'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = "local variable '{name}' is declared {kind} but never assigned"

Default diagnostic message.

severity: ClassVar[Severity] = 'warning'

Default severity. None = ERROR.

node_types: ClassVar[set[NodeType] | None] = {NodeType.MODULE}

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

metadata_dependencies: ClassVar[set[type]] = {<class 'rude.providers.ScopeProvider'>}

Required metadata providers.

check(node)[source]

Check for global/nonlocal declarations using pre-computed list from Rust.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pyflakes.UnusedVariable[source]

Bases: Rule

F841: Local variable is assigned but never used.

Ported from flake8/pyflakes.

Example:

def foo():
    x = 1      # F841 - x is never used
    y = 2
    return y

Configuration:

[tool.rude.rules.F841]
ignore_prefixes = ["_", "unused_"]

Optimized: Uses pre-computed unused_variables from Rust SemanticModel.

code: ClassVar[str] = 'F841'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = "Local variable '{name}' is assigned but never used"

Default diagnostic message.

severity: ClassVar[Severity] = 'warning'

Default severity. None = ERROR.

node_types: ClassVar[set[NodeType] | None] = {NodeType.MODULE}

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

metadata_dependencies: ClassVar[set[type]] = {<class 'rude.providers.ScopeProvider'>}

Required metadata providers.

configure(options)[source]

Configure rule from [tool.rude.rules.XXXX].

Parameters:

options (dict[str, Any])

Return type:

None

check(node)[source]

Check for unused variables using pre-computed list from Rust.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pyflakes.YieldOutsideFunction[source]

Bases: Rule

F704: yield or yield from outside of a function.

Rationale: A yield at module level is a SyntaxError.

Example:

# Bad
yield 1  # F704 - not inside a function

# Good
def gen():
    yield 1
code: ClassVar[str] = 'F704'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = "'{keyword}' outside function"

Default diagnostic message.

severity: ClassVar[Severity] = 'error'

Default severity. None = ERROR.

node_types: ClassVar[set[NodeType] | None] = {NodeType.YIELD}

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

metadata_dependencies: ClassVar[set[type]] = {<class 'rude.providers.ScopeProvider'>}

Required metadata providers.

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

Pycodestyle

Pycodestyle rules for Rude.

E: Errors - style errors W: Warnings - style warnings

Categories: - E1xx: Indentation - E2xx: Whitespace - E3xx: Blank lines - E4xx: Imports - E5xx: Line length - E7xx: Statements - W1xx-W6xx: Warnings

class rude.rules.pycodestyle.AmbiguousClassName[source]

Bases: Rule

E742: Ambiguous class name.

Rationale: Single-letter class names like I, O, l are easily confused with digits in many fonts.

Example:

class I:        # E742
    pass

class Index:    # OK
    pass
code: ClassVar[str] = 'E742'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = "ambiguous class name '{name}'"

Default diagnostic message.

node_types: ClassVar[set[NodeType] | None] = {NodeType.CLASS_DEFINITION}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pycodestyle.AmbiguousFunctionName[source]

Bases: Rule

E743: Ambiguous function name.

Rationale: Single-letter function names like I, O, l are easily confused with digits in many fonts.

Example:

def l():        # E743
    pass

def length():   # OK
    pass
code: ClassVar[str] = 'E743'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = "ambiguous function name '{name}'"

Default diagnostic message.

node_types: ClassVar[set[NodeType] | None] = {NodeType.FUNCTION_DEFINITION}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pycodestyle.AmbiguousVariableName[source]

Bases: Rule

E741: Ambiguous variable name.

Rationale: The names l, O, I are easily confused with 1, 0, l in many fonts.

Example:

l = 1       # E741
O = 2       # E741
I = 3       # E741

length = 1  # OK
code: ClassVar[str] = 'E741'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = "ambiguous variable name '{name}'"

Default diagnostic message.

node_types: ClassVar[set[NodeType] | None] = {NodeType.ASSIGNMENT, NodeType.FOR_STATEMENT, NodeType.WITH_STATEMENT}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pycodestyle.BareExcept[source]

Bases: Rule

E722: Do not use bare ‘except’.

Rationale: A bare except: catches all exceptions including KeyboardInterrupt and SystemExit, which is almost never intended.

Example:

try:
    x = 1
except:             # E722
    pass

try:
    x = 1
except Exception:   # OK
    pass
code: ClassVar[str] = 'E722'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = "do not use bare 'except'"

Default diagnostic message.

node_types: ClassVar[set[NodeType] | None] = {NodeType.EXCEPT_CLAUSE}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pycodestyle.BlankLineAtEndOfFile[source]

Bases: Rule

W391: Blank line at end of file.

Rationale: Trailing blank lines add no value and create noisy diffs.

Example:

x = 1
\n<EOF>       # W391 - trailing blank line

x = 1\n<EOF>  # OK
code: ClassVar[str] = 'W391'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'blank line at end of file'

Default diagnostic message.

node_types: ClassVar[set[NodeType] | None] = {NodeType.MODULE}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pycodestyle.BlankLineContainsWhitespace[source]

Bases: LineRule

W293: Blank line contains whitespace.

Rationale: Invisible whitespace on blank lines creates noisy diffs and wastes bytes.

Example:

x = 1
    \n        # W293 - blank line with spaces
y = 2

x = 1
\n            # OK - truly blank
y = 2
code: ClassVar[str] = 'W293'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'blank line contains whitespace'

Default diagnostic message.

uses_line_infos: ClassVar[bool] = True

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

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.rules.pycodestyle.BlankLinesAfterDecorator[source]

Bases: Rule

E304: Blank lines found after function decorator.

Rationale: A blank line between a decorator and the function it decorates is misleading and violates PEP 8.

Example:

@decorator

def foo():      # E304
    pass

@decorator
def foo():      # OK
    pass
code: ClassVar[str] = 'E304'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'blank lines found after function decorator'

Default diagnostic message.

node_types: ClassVar[set[NodeType] | None] = {NodeType.DECORATED_DEFINITION}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pycodestyle.BlockCommentShouldStartWithSpace[source]

Bases: LineRule

E265: Block comment should start with ‘# ‘.

Rationale: PEP 8 requires a space after # in block comments for readability.

Example:

#comment            # E265
# comment           # OK
#: Sphinx docstring # OK
#                   # OK (empty comment)
code: ClassVar[str] = 'E265'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = "block comment should start with '# '"

Default diagnostic message.

uses_line_infos: ClassVar[bool] = True

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

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]

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]

class rude.rules.pycodestyle.ComparisonToNone[source]

Bases: Rule

E711: Comparison to None should use ‘is’ or ‘is not’.

Rationale: None is a singleton, so identity checks (is) are more correct and faster than equality checks (==).

Example:

x == None    # E711 - use 'x is None'
x != None    # E711 - use 'x is not None'

x is None    # OK
x is not None  # OK
code: ClassVar[str] = 'E711'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = "comparison to None should be 'if cond is None:' or 'if cond is not None:'"

Default diagnostic message.

node_types: ClassVar[set[NodeType] | None] = {NodeType.COMPARISON_OPERATOR}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pycodestyle.ComparisonToTrueFalse[source]

Bases: Rule

E712: Comparison to True/False should use ‘if cond:’ or ‘if not cond:’.

Rationale: Comparing to True/False with == is redundant. Use the value directly in a boolean context.

Example:

x == True    # E712 - use 'if x:'
x == False   # E712 - use 'if not x:'
x != True    # E712 - use 'if not x:'

if x:        # OK
if not x:    # OK
x is True    # OK for singletons
code: ClassVar[str] = 'E712'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = "comparison to True should be 'if cond:' or 'if cond is True:'"

Default diagnostic message.

node_types: ClassVar[set[NodeType] | None] = {NodeType.COMPARISON_OPERATOR}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pycodestyle.ExpectedOneBlankLine[source]

Bases: Rule

E301: Expected 1 blank line, found 0.

Rationale: PEP 8 requires one blank line between method definitions in a class for readability.

Example:

class Foo:
    def bar(self):
        pass
    def baz(self):    # E301
        pass

class Foo:
    def bar(self):
        pass

    def baz(self):    # OK
        pass
code: ClassVar[str] = 'E301'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'expected 1 blank line, found 0'

Default diagnostic message.

node_types: ClassVar[set[NodeType] | None] = {NodeType.FUNCTION_DEFINITION}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pycodestyle.ExpectedOneBlankLineBeforeNestedDef[source]

Bases: Rule

E306: Expected 1 blank line before a nested definition.

Rationale: PEP 8 requires a blank line before a nested function or class to visually separate it from surrounding code.

Example:

def foo():
    x = 1
    def bar():      # E306
        pass

def foo():
    x = 1

    def bar():      # OK
        pass
code: ClassVar[str] = 'E306'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'expected 1 blank line before a nested definition, found {found}'

Default diagnostic message.

node_types: ClassVar[set[NodeType] | None] = {NodeType.CLASS_DEFINITION, NodeType.FUNCTION_DEFINITION}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pycodestyle.ExpectedTwoBlankLines[source]

Bases: Rule

E302: Expected 2 blank lines, found N.

Rationale: PEP 8 requires two blank lines before top-level function or class definitions.

Example:

def foo():
    pass
def bar():      # E302
    pass

def foo():
    pass


def bar():      # OK
    pass
code: ClassVar[str] = 'E302'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'expected 2 blank lines, found {found}'

Default diagnostic message.

node_types: ClassVar[set[NodeType] | None] = {NodeType.CLASS_DEFINITION, NodeType.FUNCTION_DEFINITION}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pycodestyle.ExpectedTwoBlankLinesAfterClassOrFunction[source]

Bases: Rule

E305: Expected 2 blank lines after class or function definition.

Rationale: PEP 8 requires two blank lines after top-level definitions to visually separate them from module-level code.

Example:

class Foo:
    pass
x = 1           # E305

class Foo:
    pass


x = 1           # OK
code: ClassVar[str] = 'E305'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'expected 2 blank lines after class or function definition, found {found}'

Default diagnostic message.

node_types: ClassVar[set[NodeType] | None] = {NodeType.ASSIGNMENT, NodeType.EXPRESSION_STATEMENT, NodeType.IMPORT_FROM_STATEMENT, NodeType.IMPORT_STATEMENT}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pycodestyle.IndentationContainsMixedSpacesAndTabs[source]

Bases: LineRule

E101: Indentation contains mixed spaces and tabs.

Rationale: Mixing tabs and spaces makes indentation ambiguous and can cause TabError in Python 3.

Example:

def foo():
         x = 1     # E101 - tab after spaces

def foo():
    x = 1    # OK - spaces only
code: ClassVar[str] = 'E101'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'indentation contains mixed spaces and tabs'

Default diagnostic message.

uses_line_infos: ClassVar[bool] = True

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

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.rules.pycodestyle.IndentationContainsTabs[source]

Bases: LineRule

W191: Indentation contains tabs.

Rationale: PEP 8 requires spaces for indentation. Tabs render inconsistently across editors.

Example:

def foo():
        x = 1     # W191 - tab used for indentation

def foo():
    x = 1   # OK - spaces only
code: ClassVar[str] = 'W191'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'indentation contains tabs'

Default diagnostic message.

severity: ClassVar[Severity] = 'warning'

Default severity. None = ERROR.

uses_line_infos: ClassVar[bool] = True

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

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.rules.pycodestyle.IndentationNotMultipleOfFour[source]

Bases: LineRule

E111: Indentation is not a multiple of the configured indent size.

Rationale: PEP 8 recommends 4-space indentation. Inconsistent indentation reduces readability.

Example:

if True:
   x = 1     # E111 - 3 spaces, not 4

if True:
    x = 1    # OK - 4 spaces
Configuration:

[tool.rude.rules.E111] indent_size = 4 # default

code: ClassVar[str] = 'E111'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'indentation is not a multiple of {indent_size}'

Default diagnostic message.

uses_line_infos: ClassVar[bool] = True

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

configure(options)[source]

Configure rule from [tool.rude.rules.XXXX].

Parameters:

options (dict[str, Any])

Return type:

None

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.rules.pycodestyle.InlineCommentShouldStartWithSpace[source]

Bases: LineRule

E262: Inline comment should start with ‘# ‘.

Rationale: PEP 8 requires a space after # in comments for readability.

Example:

x = 1  #comment     # E262
x = 1  # comment    # OK
code: ClassVar[str] = 'E262'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = "inline comment should start with '# '"

Default diagnostic message.

uses_line_infos: ClassVar[bool] = True

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

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]

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]

class rude.rules.pycodestyle.InvalidEscapeSequence[source]

Bases: Rule

W605: Invalid escape sequence.

Rationale: Invalid escape sequences raise DeprecationWarning in Python 3.12+ and will become SyntaxError in a future version.

Example:

x = "\d+"      # W605 - invalid escape sequence

x = r"\d+"     # OK - raw string
x = "\\d+"    # OK - escaped backslash
code: ClassVar[str] = 'W605'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = "invalid escape sequence '\\{char}'"

Default diagnostic message.

node_types: ClassVar[set[NodeType] | None] = {NodeType.STRING}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pycodestyle.LambdaAssignment[source]

Bases: Rule

E731: Do not assign a lambda expression, use a def.

Rationale: Assigning a lambda defeats its purpose as an anonymous function. A def provides a name for tracebacks and is clearer.

Example:

f = lambda x: x + 1     # E731

def f(x):               # OK
    return x + 1
code: ClassVar[str] = 'E731'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'do not assign a lambda expression, use a def'

Default diagnostic message.

node_types: ClassVar[set[NodeType] | None] = {NodeType.ASSIGNMENT}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pycodestyle.LineTooLong[source]

Bases: Rule

E501: Line too long.

Rationale: PEP 8 recommends a maximum line length of 79 characters for readability and side-by-side diff viewing.

Example:

# Bad
x = "this is a very long line that exceeds the maximum line length limit"  # E501

# Good
x = (
    "this is a long line that has been"
    " wrapped for readability"
)
Configuration:

[tool.rude.rules.E501] max_line_length = 79 # default

code: ClassVar[str] = 'E501'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'line too long ({length} > {max_length} characters)'

Default diagnostic message.

node_types: ClassVar[set[NodeType] | None] = {NodeType.MODULE}

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

configure(options)[source]

Configure rule from [tool.rude.rules.XXXX].

Parameters:

options (dict[str, Any])

Return type:

None

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pycodestyle.MissingWhitespaceAfterComma[source]

Bases: Rule

E231: Missing whitespace after ‘,’, ‘;’, or ‘:’.

Rationale: PEP 8 requires a space after commas, semicolons, and colons for readability.

Example:

[1,2,3]         # E231 (multiple)
[1, 2, 3]       # OK
code: ClassVar[str] = 'E231'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = "missing whitespace after '{char}'"

Default diagnostic message.

node_types: ClassVar[set[NodeType] | None] = {NodeType.ARGUMENT_LIST, NodeType.DICTIONARY, NodeType.LIST, NodeType.PAIR, NodeType.PARAMETERS, NodeType.TUPLE, NodeType.TYPED_PARAMETER}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pycodestyle.MissingWhitespaceAfterKeyword[source]

Bases: Rule

E275: Missing whitespace after keyword.

Rationale: PEP 8 requires a space between keywords and opening parentheses.

Uses regex + tree-sitter point check to avoid false positives in strings. This is 17x faster than token-based checking.

Example:

if(x):          # E275
if (x):         # OK
x = "if(x)"     # OK (no false positive)
code: ClassVar[str] = 'E275'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'missing whitespace after keyword'

Default diagnostic message.

node_types: ClassVar[set[NodeType] | None] = {NodeType.MODULE}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pycodestyle.MissingWhitespaceAroundArithmeticOperator[source]

Bases: Rule

E226: Missing whitespace around arithmetic operator.

Rationale: PEP 8 allows omitting spaces around arithmetic operators for grouping, but consistent spacing improves readability. This rule is ignored by default per pycodestyle convention.

Example:

c = (a+b) * (a-b)   # E226
c = (a + b) * (a - b)   # OK
code: ClassVar[str] = 'E226'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'missing whitespace around arithmetic operator'

Default diagnostic message.

node_types: ClassVar[set[NodeType] | None] = {NodeType.BINARY_OPERATOR}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pycodestyle.MissingWhitespaceAroundBitwiseOperator[source]

Bases: Rule

E227: Missing whitespace around bitwise or shift operator.

Rationale: PEP 8 requires spaces around bitwise and shift operators for readability.

Example:

x = x|y         # E227
x = x | y       # OK
code: ClassVar[str] = 'E227'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'missing whitespace around bitwise or shift operator'

Default diagnostic message.

node_types: ClassVar[set[NodeType] | None] = {NodeType.BINARY_OPERATOR}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pycodestyle.MissingWhitespaceAroundModuloOperator[source]

Bases: Rule

E228: Missing whitespace around modulo operator.

Rationale: PEP 8 requires spaces around the modulo operator for readability.

Example:

x = x%y         # E228
x = x % y       # OK
code: ClassVar[str] = 'E228'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'missing whitespace around modulo operator'

Default diagnostic message.

node_types: ClassVar[set[NodeType] | None] = {NodeType.BINARY_OPERATOR}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pycodestyle.MissingWhitespaceAroundOperator[source]

Bases: Rule

E225: Missing whitespace around operator.

Rationale: PEP 8 requires spaces around assignment, comparison, and binary operators for readability.

Example:

i=i+1           # E225
i = i + 1       # OK
code: ClassVar[str] = 'E225'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'missing whitespace around operator'

Default diagnostic message.

node_types: ClassVar[set[NodeType] | None] = {NodeType.ASSIGNMENT, NodeType.AUGMENTED_ASSIGNMENT, NodeType.BINARY_OPERATOR, NodeType.COMPARISON_OPERATOR}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pycodestyle.ModuleLevelImportNotAtTop[source]

Bases: Rule

E402: Module level import not at top of file.

Imports should be at the top of the file, after any module docstring and comments, but before any other code.

Example:

x = 1
import os           # E402

import os           # OK
x = 1
code: ClassVar[str] = 'E402'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'module level import not at top of file'

Default diagnostic message.

node_types: ClassVar[set[NodeType] | None] = {NodeType.IMPORT_FROM_STATEMENT, NodeType.IMPORT_STATEMENT}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pycodestyle.MultipleImportsOnOneLine[source]

Bases: Rule

E401: Multiple imports on one line.

Rationale: PEP 8 requires each import on its own line for clarity and cleaner diffs.

Example:

import os, sys      # E401

import os           # OK
import sys
code: ClassVar[str] = 'E401'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'multiple imports on one line'

Default diagnostic message.

node_types: ClassVar[set[NodeType] | None] = {NodeType.IMPORT_STATEMENT}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pycodestyle.MultipleSpacesAfterComma[source]

Bases: LineRule

E241: Multiple spaces after ‘,’, ‘;’, or ‘:’.

Rationale: PEP 8 requires exactly one space after commas and semicolons. This rule is ignored by default per pycodestyle convention.

Example:

a = (1,  2)     # E241
a = (1, 2)      # OK
code: ClassVar[str] = 'E241'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = "multiple spaces after '{char}'"

Default diagnostic message.

uses_line_infos: ClassVar[bool] = True

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

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]

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]

class rude.rules.pycodestyle.MultipleSpacesAfterKeyword[source]

Bases: LineRule

E271: Multiple spaces after keyword.

Rationale: PEP 8 requires exactly one space after keywords.

Example:

if  x:          # E271
if x:           # OK
code: ClassVar[str] = 'E271'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'multiple spaces after keyword'

Default diagnostic message.

uses_line_infos: ClassVar[bool] = True

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

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]

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]

class rude.rules.pycodestyle.MultipleSpacesAfterOperator[source]

Bases: LineRule

E222: Multiple spaces after operator.

Rationale: PEP 8 requires exactly one space around operators.

Example:

a = 4 +  5      # E222
a = 4 + 5       # OK
code: ClassVar[str] = 'E222'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'multiple spaces after operator'

Default diagnostic message.

uses_line_infos: ClassVar[bool] = True

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

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]

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]

class rude.rules.pycodestyle.MultipleSpacesBeforeKeyword[source]

Bases: LineRule

E272: Multiple spaces before keyword.

Rationale: PEP 8 requires exactly one space before keywords.

Example:

True  and False     # E272
True and False      # OK
code: ClassVar[str] = 'E272'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'multiple spaces before keyword'

Default diagnostic message.

uses_line_infos: ClassVar[bool] = True

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

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]

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]

class rude.rules.pycodestyle.MultipleSpacesBeforeOperator[source]

Bases: LineRule

E221: Multiple spaces before operator.

Rationale: PEP 8 requires exactly one space around operators (except for alignment, which is discouraged).

Example:

a = 4  + 5      # E221
a = 4 + 5       # OK
code: ClassVar[str] = 'E221'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'multiple spaces before operator'

Default diagnostic message.

uses_line_infos: ClassVar[bool] = True

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

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]

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]

class rude.rules.pycodestyle.MultipleStatementsOnOneLineColon[source]

Bases: Rule

E701: Multiple statements on one line (colon).

Rationale: PEP 8 requires compound statements to have the body on a separate line for readability.

Example:

if x: return y      # E701

if x:               # OK
    return y
code: ClassVar[str] = 'E701'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'multiple statements on one line (colon)'

Default diagnostic message.

node_types: ClassVar[set[NodeType] | None] = {NodeType.ELIF_CLAUSE, NodeType.ELSE_CLAUSE, NodeType.EXCEPT_CLAUSE, NodeType.FINALLY_CLAUSE, NodeType.FOR_STATEMENT, NodeType.IF_STATEMENT, NodeType.TRY_STATEMENT, NodeType.WHILE_STATEMENT, NodeType.WITH_STATEMENT}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pycodestyle.MultipleStatementsOnOneLineDef[source]

Bases: Rule

E704: Multiple statements on one line (def).

Rationale: PEP 8 requires function bodies on a separate line for readability and consistent style.

Example:

def f(): return 1   # E704

def f():            # OK
    return 1
code: ClassVar[str] = 'E704'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'multiple statements on one line (def)'

Default diagnostic message.

node_types: ClassVar[set[NodeType] | None] = {NodeType.FUNCTION_DEFINITION}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pycodestyle.MultipleStatementsOnOneLineSemicolon[source]

Bases: Rule

E702: Multiple statements on one line (semicolon).

Rationale: PEP 8 discourages semicolons to separate statements. Use separate lines instead.

Example:

x = 1; y = 2        # E702

x = 1               # OK
y = 2
code: ClassVar[str] = 'E702'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'multiple statements on one line (semicolon)'

Default diagnostic message.

node_types: ClassVar[set[NodeType] | None] = {NodeType.ASSIGNMENT, NodeType.BREAK_STATEMENT, NodeType.CONTINUE_STATEMENT, NodeType.EXPRESSION_STATEMENT, NodeType.PASS_STATEMENT, NodeType.RETURN_STATEMENT}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pycodestyle.NoNewlineAtEndOfFile[source]

Bases: Rule

W292: No newline at end of file.

Rationale: POSIX requires text files to end with a newline. Missing newlines cause issues with some tools and diffs.

Example:

x = 1<EOF>      # W292 - missing final newline

x = 1\n<EOF>   # OK
code: ClassVar[str] = 'W292'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'no newline at end of file'

Default diagnostic message.

node_types: ClassVar[set[NodeType] | None] = {NodeType.MODULE}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pycodestyle.NotInTest[source]

Bases: Rule

E713: Test for membership should be ‘not in’.

Rationale: not x in y is harder to read than the idiomatic x not in y.

Example:

not x in y      # E713 - use 'x not in y'

x not in y      # OK
code: ClassVar[str] = 'E713'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = "test for membership should be 'not in'"

Default diagnostic message.

node_types: ClassVar[set[NodeType] | None] = {NodeType.NOT_OPERATOR}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pycodestyle.NotIsTest[source]

Bases: Rule

E714: Test for object identity should be ‘is not’.

Rationale: not x is y is harder to read than the idiomatic x is not y.

Example:

not x is y      # E714 - use 'x is not y'

x is not y      # OK
code: ClassVar[str] = 'E714'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = "test for object identity should be 'is not'"

Default diagnostic message.

node_types: ClassVar[set[NodeType] | None] = {NodeType.NOT_OPERATOR}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pycodestyle.OverIndented[source]

Bases: Rule

E117: Over-indented.

Rationale: Over-indentation misrepresents the logical structure and reduces readability.

Example:

if True:
        x = 1     # E117 - too many spaces

if True:
    x = 1         # OK
code: ClassVar[str] = 'E117'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'over-indented'

Default diagnostic message.

node_types: ClassVar[set[NodeType] | None] = {NodeType.BLOCK}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pycodestyle.StatementEndsWithSemicolon[source]

Bases: Rule

E703: Statement ends with semicolon.

Rationale: Trailing semicolons are unnecessary in Python and are a common artifact from C/Java habits.

Example:

x = 1;              # E703

x = 1               # OK
code: ClassVar[str] = 'E703'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'statement ends with a semicolon'

Default diagnostic message.

node_types: ClassVar[set[NodeType] | None] = {NodeType.MODULE}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pycodestyle.TabAfterComma[source]

Bases: LineRule

E242: Tab after ‘,’, ‘;’, or ‘:’.

Rationale: PEP 8 requires spaces, not tabs, after commas and semicolons. This rule is ignored by default per pycodestyle convention.

Example:

a = (1,\t2)    # E242
a = (1, 2)      # OK
code: ClassVar[str] = 'E242'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = "tab after '{char}'"

Default diagnostic message.

uses_line_infos: ClassVar[bool] = True

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

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]

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]

class rude.rules.pycodestyle.TabAfterKeyword[source]

Bases: LineRule

E273: Tab after keyword.

Rationale: PEP 8 requires spaces, not tabs, after keywords.

Example:

if\tx:         # E273
if x:           # OK
code: ClassVar[str] = 'E273'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'tab after keyword'

Default diagnostic message.

uses_line_infos: ClassVar[bool] = True

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

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]

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]

class rude.rules.pycodestyle.TabAfterOperator[source]

Bases: LineRule

E224: Tab after operator.

Rationale: PEP 8 requires spaces, not tabs, around operators.

Example:

a = 4 +\t5     # E224
a = 4 + 5       # OK
code: ClassVar[str] = 'E224'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'tab after operator'

Default diagnostic message.

uses_line_infos: ClassVar[bool] = True

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

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]

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]

class rude.rules.pycodestyle.TabBeforeKeyword[source]

Bases: LineRule

E274: Tab before keyword.

Rationale: PEP 8 requires spaces, not tabs, before keywords.

Example:

True\tand False    # E274
True and False      # OK
code: ClassVar[str] = 'E274'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'tab before keyword'

Default diagnostic message.

uses_line_infos: ClassVar[bool] = True

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

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]

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]

class rude.rules.pycodestyle.TabBeforeOperator[source]

Bases: LineRule

E223: Tab before operator.

Rationale: PEP 8 requires spaces, not tabs, around operators.

Example:

a = 4\t+ 5     # E223
a = 4 + 5       # OK
code: ClassVar[str] = 'E223'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'tab before operator'

Default diagnostic message.

uses_line_infos: ClassVar[bool] = True

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

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]

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]

class rude.rules.pycodestyle.TooManyBlankLines[source]

Bases: Rule

E303: Too many blank lines (N).

Rationale: PEP 8 limits consecutive blank lines to two at the top level and one inside functions/classes.

Example:

# Bad
def foo():
    pass



def bar():      # E303 - 3 blank lines
    pass

# Good
def foo():
    pass


def bar():
    pass
code: ClassVar[str] = 'E303'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'too many blank lines ({count})'

Default diagnostic message.

node_types: ClassVar[set[NodeType] | None] = {NodeType.MODULE}

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

configure(options)[source]

Configure rule from [tool.rude.rules.XXXX].

Parameters:

options (dict[str, Any])

Return type:

None

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pycodestyle.TooManyHashesForBlockComment[source]

Bases: LineRule

E266: Too many leading ‘#’ for block comment.

Rationale: PEP 8 requires block comments to start with a single # followed by a space.

Example:

## comment          # E266
# comment           # OK
### header ###      # OK (separator)
code: ClassVar[str] = 'E266'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = "too many leading '#' for block comment"

Default diagnostic message.

uses_line_infos: ClassVar[bool] = True

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

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]

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]

class rude.rules.pycodestyle.TrailingWhitespace[source]

Bases: LineRule

W291: Trailing whitespace.

Rationale: Trailing whitespace creates noisy diffs and is banned by PEP 8.

Example:

x = 1   \n    # W291 - trailing spaces

x = 1\n       # OK
code: ClassVar[str] = 'W291'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'trailing whitespace'

Default diagnostic message.

uses_line_infos: ClassVar[bool] = True

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

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.rules.pycodestyle.TwoSpacesBeforeInlineComment[source]

Bases: LineRule

E261: At least two spaces before inline comment.

Rationale: PEP 8 requires at least two spaces before an inline comment to visually separate code from comments.

Example:

x = 1 # comment     # E261
x = 1  # comment    # OK
code: ClassVar[str] = 'E261'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'at least two spaces before inline comment'

Default diagnostic message.

uses_line_infos: ClassVar[bool] = True

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

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]

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]

class rude.rules.pycodestyle.TypeComparison[source]

Bases: Rule

E721: Do not compare types, use isinstance().

Rationale: isinstance() correctly handles subclasses, while type() comparison does not.

Example:

type(x) == int       # E721 - use isinstance(x, int)
type(x) == type(y)   # E721 - use isinstance(x, type(y))

isinstance(x, int)   # OK
code: ClassVar[str] = 'E721'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = "do not compare types, use 'isinstance()'"

Default diagnostic message.

node_types: ClassVar[set[NodeType] | None] = {NodeType.COMPARISON_OPERATOR}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pycodestyle.UnexpectedSpacesAroundKeywordEquals[source]

Bases: Rule

E251: Unexpected spaces around keyword / parameter equals.

Rationale: PEP 8 requires no spaces around = in default parameter values and keyword arguments.

Example:

def foo(x = 1):     # E251
def foo(x=1):       # OK
code: ClassVar[str] = 'E251'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = 'unexpected spaces around keyword / parameter equals'

Default diagnostic message.

node_types: ClassVar[set[NodeType] | None] = {NodeType.DEFAULT_PARAMETER, NodeType.KEYWORD_ARGUMENT}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pycodestyle.WhitespaceAfterOpenBracket[source]

Bases: Rule

E201: Whitespace after ‘(’, ‘[’, or ‘{‘.

Rationale: PEP 8 requires no whitespace immediately after opening brackets.

Example:

spam( ham)      # E201
spam(ham)       # OK
code: ClassVar[str] = 'E201'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = "whitespace after '{bracket}'"

Default diagnostic message.

node_types: ClassVar[set[NodeType] | None] = {NodeType.ARGUMENT_LIST, NodeType.DICTIONARY, NodeType.LIST, NodeType.PARAMETERS, NodeType.SET, NodeType.SUBSCRIPT, NodeType.TUPLE}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pycodestyle.WhitespaceBeforeCloseBracket[source]

Bases: Rule

E202: Whitespace before ‘)’, ‘]’, or ‘}’.

Rationale: PEP 8 requires no whitespace immediately before closing brackets.

Example:

spam(ham )      # E202
spam(ham)       # OK
code: ClassVar[str] = 'E202'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = "whitespace before '{bracket}'"

Default diagnostic message.

node_types: ClassVar[set[NodeType] | None] = {NodeType.ARGUMENT_LIST, NodeType.DICTIONARY, NodeType.LIST, NodeType.PARAMETERS, NodeType.SET, NodeType.SUBSCRIPT, NodeType.TUPLE}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pycodestyle.WhitespaceBeforeColon[source]

Bases: Rule

E203: Whitespace before ‘:’ or ‘,’.

Rationale: PEP 8 requires no whitespace immediately before colons, commas, or semicolons.

Example:

spam[1 :]       # E203
spam[1:]        # OK
code: ClassVar[str] = 'E203'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = "whitespace before '{char}'"

Default diagnostic message.

node_types: ClassVar[set[NodeType] | None] = {NodeType.ARGUMENT_LIST, NodeType.DICTIONARY, NodeType.PAIR, NodeType.PARAMETERS, NodeType.SLICE}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

class rude.rules.pycodestyle.WhitespaceBeforeParameters[source]

Bases: Rule

E211: Whitespace before ‘(’ in function call.

Rationale: PEP 8 requires no whitespace between a function name and its argument list.

Example:

spam (1)        # E211
spam(1)         # OK
code: ClassVar[str] = 'E211'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = "whitespace before '('"

Default diagnostic message.

node_types: ClassVar[set[NodeType] | None] = {NodeType.CALL}

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

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

McCabe

McCabe complexity rules for Rude.

C9xx: Complexity

class rude.rules.mccabe.FunctionTooComplex[source]

Bases: Rule

C901: Function is too complex (cyclomatic complexity).

Cyclomatic complexity measures the number of independent paths through a function. High complexity indicates code that is hard to test and maintain.

Complexity is calculated as:

1 (base) + if + elif + for + while + except + ternary + case

Example:

# Bad
def complex_function(x):    # C901 if complexity > threshold
    if x > 0:               # +1
        if x > 10:          # +1
            return "big"
        elif x > 5:         # +1
            return "medium"
    for i in range(x):      # +1
        if i % 2 == 0:      # +1
            print(i)
    return "small"
    # Total: 1 + 5 = 6

# Good - extract branches into helpers
def process(x):
    if x > 0:
        return handle_positive(x)
    return handle_range(x)
Configuration:

[tool.rude.rules.C901] max_complexity = 10 # default

code: ClassVar[str] = 'C901'

Unique rule code (e.g., ‘S001’, ‘ACME001’).

message: ClassVar[str] = "'{name}' is too complex ({complexity})"

Default diagnostic message.

node_types: ClassVar[set[NodeType] | None] = {NodeType.FUNCTION_DEFINITION}

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

configure(options)[source]

Configure rule from [tool.rude.rules.XXXX].

Parameters:

options (dict[str, Any])

Return type:

None

check(node)[source]

Check a node and yield diagnostics.

Parameters:

node (Node)

Return type:

Iterator[Diagnostic]

Example Rules

Patterns (PAT), hygiene (META), and templates (EX) rules are available in examples/rules/ for use as local rules. See examples/rules/README.md.