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:
RuleF631: 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
- message: ClassVar[str] = 'assertion test is a non-empty tuple, which is always True'¶
Default diagnostic message.
- node_types: ClassVar[set[NodeType] | None] = {NodeType.ASSERT_STATEMENT}¶
Tree-sitter node types to match. None = all nodes (discouraged).
- class rude.rules.pyflakes.BreakOutsideLoop[source]¶
Bases:
RuleF701: break not properly in loop.
Rationale:
breakoutside a loop is aSyntaxError.Example:
# Bad break # F701 - not inside a loop # Good while True: break
- 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.
- class rude.rules.pyflakes.ContinueOutsideLoop[source]¶
Bases:
RuleF702: continue not properly in loop.
Rationale:
continueoutside a loop is aSyntaxError.Example:
# Bad continue # F702 - not inside a loop # Good for i in range(10): continue
- 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.
- class rude.rules.pyflakes.DefaultExceptNotLast[source]¶
Bases:
RuleF707: A bare except: clause must be the last exception handler.
Rationale: A bare
except:before a typed handler is aSyntaxErrorbecause 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
- message: ClassVar[str] = 'an except clause without an exception type must be last'¶
Default diagnostic message.
- node_types: ClassVar[set[NodeType] | None] = {NodeType.TRY_STATEMENT}¶
Tree-sitter node types to match. None = all nodes (discouraged).
- class rude.rules.pyflakes.DoctestSyntaxError[source]¶
Bases:
RuleF721: 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
- node_types: ClassVar[set[NodeType] | None] = {NodeType.STRING}¶
Tree-sitter node types to match. None = all nodes (discouraged).
- class rude.rules.pyflakes.DuplicateArgument[source]¶
Bases:
RuleF831: Duplicate argument in function definition.
Rationale: Duplicate parameter names cause a
SyntaxErrorin Python 3.Example:
# Bad def foo(a, a): # F831 - duplicate argument 'a' pass # Good def foo(a, b): pass
- message: ClassVar[str] = "duplicate argument '{name}' in function definition"¶
Default diagnostic message.
- node_types: ClassVar[set[NodeType] | None] = {NodeType.FUNCTION_DEFINITION, NodeType.LAMBDA}¶
Tree-sitter node types to match. None = all nodes (discouraged).
- class rude.rules.pyflakes.FStringMissingPlaceholders[source]¶
Bases:
_PrefixStringMissingPlaceholdersF541: 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
- class rude.rules.pyflakes.ForwardAnnotationSyntaxError[source]¶
Bases:
RuleF722: Syntax error in forward annotation.
Rationale: A forward annotation with invalid syntax will raise a
SyntaxErrorwhen evaluated at runtime or by type checkers.Example:
# Bad x: "List[int" # F722 - unclosed bracket # Good x: "List[int]"
- message: ClassVar[str] = 'syntax error in forward annotation {annotation!r}'¶
Default diagnostic message.
- node_types: ClassVar[set[NodeType] | None] = {NodeType.STRING}¶
Tree-sitter node types to match. None = all nodes (discouraged).
- class rude.rules.pyflakes.FutureFeatureNotDefined[source]¶
Bases:
RuleF407: Undefined name in __future__ import.
Example:
from __future__ import nonexistent_feature # F407 from __future__ import annotations # OK
- node_types: ClassVar[set[NodeType] | None] = {NodeType.FUTURE_IMPORT_STATEMENT, NodeType.IMPORT_FROM_STATEMENT}¶
Tree-sitter node types to match. None = all nodes (discouraged).
- class rude.rules.pyflakes.IfTuple[source]¶
Bases:
RuleF634: 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
- message: ClassVar[str] = 'if test is a non-empty tuple, which is always True'¶
Default diagnostic message.
- node_types: ClassVar[set[NodeType] | None] = {NodeType.IF_STATEMENT}¶
Tree-sitter node types to match. None = all nodes (discouraged).
- class rude.rules.pyflakes.ImportShadowedByLoopVar[source]¶
Bases:
RuleF402: 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.
- message: ClassVar[str] = "import '{name}' from line {line} shadowed by loop variable"¶
Default diagnostic message.
- 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.
- class rude.rules.pyflakes.ImportStarNotPermitted[source]¶
Bases:
RuleF406: 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
- message: ClassVar[str] = "'from {module} import *' only allowed at module level"¶
Default diagnostic message.
- node_types: ClassVar[set[NodeType] | None] = {NodeType.IMPORT_FROM_STATEMENT}¶
Tree-sitter node types to match. None = all nodes (discouraged).
- class rude.rules.pyflakes.ImportStarUsed[source]¶
Bases:
RuleF403: 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
- message: ClassVar[str] = "'from {module} import *' used; unable to detect undefined names"¶
Default diagnostic message.
- node_types: ClassVar[set[NodeType] | None] = {NodeType.IMPORT_FROM_STATEMENT}¶
Tree-sitter node types to match. None = all nodes (discouraged).
- class rude.rules.pyflakes.InvalidPrintSyntax[source]¶
Bases:
RuleF633: 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
- node_types: ClassVar[set[NodeType] | None] = {NodeType.PRINT_STATEMENT}¶
Tree-sitter node types to match. None = all nodes (discouraged).
- class rude.rules.pyflakes.IsLiteral[source]¶
Bases:
RuleF632: 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
- message: ClassVar[str] = "use ==/!= to compare '{literal}', not is/is not"¶
Default diagnostic message.
- node_types: ClassVar[set[NodeType] | None] = {NodeType.COMPARISON_OPERATOR}¶
Tree-sitter node types to match. None = all nodes (discouraged).
- class rude.rules.pyflakes.LateFutureImport[source]¶
Bases:
RuleF404: 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
- message: ClassVar[str] = 'from __future__ imports must occur at the beginning of the file'¶
Default diagnostic message.
- node_types: ClassVar[set[NodeType] | None] = {NodeType.IMPORT_FROM_STATEMENT}¶
Tree-sitter node types to match. None = all nodes (discouraged).
- class rude.rules.pyflakes.MultiValueRepeatedKeyLiteral[source]¶
Bases:
RuleF601: 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
- node_types: ClassVar[set[NodeType] | None] = {NodeType.DICTIONARY}¶
Tree-sitter node types to match. None = all nodes (discouraged).
- class rude.rules.pyflakes.MultiValueRepeatedKeyVariable[source]¶
Bases:
RuleF602: 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
- node_types: ClassVar[set[NodeType] | None] = {NodeType.DICTIONARY}¶
Tree-sitter node types to match. None = all nodes (discouraged).
- class rude.rules.pyflakes.PercentFormatExpectedMapping[source]¶
Bases:
RuleF502: % format expected mapping but got sequence.
Rationale: Named placeholders like
%(name)srequire a mapping (dict), not a sequence. This causes aTypeErrorat runtime.Example:
# Bad "%(name)s" % (1, 2) # F502 - expected dict, got tuple # Good "%(name)s" % {"name": "Alice"}
- message: ClassVar[str] = 'percent format expected mapping but found sequence'¶
Default diagnostic message.
- node_types: ClassVar[set[NodeType] | None] = {NodeType.BINARY_OPERATOR}¶
Tree-sitter node types to match. None = all nodes (discouraged).
- class rude.rules.pyflakes.PercentFormatExpectedSequence[source]¶
Bases:
RuleF503: % format expected sequence but got mapping.
Rationale: Positional placeholders like
%srequire a sequence (tuple), not a mapping. This causes aTypeErrorat runtime.Example:
# Bad "%s %s" % {"a": 1} # F503 - expected tuple, got dict # Good "%s %s" % (1, 2)
- message: ClassVar[str] = 'percent format expected sequence but found mapping'¶
Default diagnostic message.
- node_types: ClassVar[set[NodeType] | None] = {NodeType.BINARY_OPERATOR}¶
Tree-sitter node types to match. None = all nodes (discouraged).
- class rude.rules.pyflakes.PercentFormatExtraNamedArguments[source]¶
Bases:
RuleF504: % 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}
- message: ClassVar[str] = 'percent format has unused named argument(s): {names}'¶
Default diagnostic message.
- node_types: ClassVar[set[NodeType] | None] = {NodeType.BINARY_OPERATOR}¶
Tree-sitter node types to match. None = all nodes (discouraged).
- class rude.rules.pyflakes.PercentFormatInvalidFormat[source]¶
Bases:
RuleF501: Invalid % format string.
Rationale: An invalid format specifier causes a
ValueErrorat runtime.Example:
# Bad "%z" % x # F501 - z is not a valid format character # Good "%s" % x
- message: ClassVar[str] = 'percent format has invalid format string: {error}'¶
Default diagnostic message.
- node_types: ClassVar[set[NodeType] | None] = {NodeType.BINARY_OPERATOR}¶
Tree-sitter node types to match. None = all nodes (discouraged).
- class rude.rules.pyflakes.PercentFormatMissingArgument[source]¶
Bases:
RuleF505: % format is missing named argument.
Rationale: A missing key causes a
KeyErrorat runtime.Example:
# Bad "%(name)s %(other)s" % {"name": 1} # F505 - missing 'other' # Good "%(name)s %(other)s" % {"name": 1, "other": 2}
- message: ClassVar[str] = 'percent format is missing argument(s): {missing}'¶
Default diagnostic message.
- node_types: ClassVar[set[NodeType] | None] = {NodeType.BINARY_OPERATOR}¶
Tree-sitter node types to match. None = all nodes (discouraged).
- class rude.rules.pyflakes.PercentFormatMixedPositionalAndNamed[source]¶
Bases:
RuleF506: % format mixes positional and named placeholders.
Rationale: Python does not support mixing positional and named placeholders in
%-formatting. This causes aTypeError.Example:
# Bad "%s %(name)s" % (1, {"name": 2}) # F506 - can't mix # Good "%(first)s %(name)s" % {"first": 1, "name": 2}
- message: ClassVar[str] = 'percent format has mixed positional and named placeholders'¶
Default diagnostic message.
- node_types: ClassVar[set[NodeType] | None] = {NodeType.BINARY_OPERATOR}¶
Tree-sitter node types to match. None = all nodes (discouraged).
- class rude.rules.pyflakes.PercentFormatPositionalCountMismatch[source]¶
Bases:
RuleF507: % format positional argument count mismatch.
Rationale: Providing the wrong number of arguments causes a
TypeErrorat runtime.Example:
# Bad "%s %s" % (1,) # F507 - expected 2 arguments, got 1 # Good "%s %s" % (1, 2)
- message: ClassVar[str] = 'percent format expected {expected} argument(s) but found {found}'¶
Default diagnostic message.
- node_types: ClassVar[set[NodeType] | None] = {NodeType.BINARY_OPERATOR}¶
Tree-sitter node types to match. None = all nodes (discouraged).
- class rude.rules.pyflakes.PercentFormatStarRequiresSequence[source]¶
Bases:
RuleF508: % 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")
- message: ClassVar[str] = 'percent format with * width/precision requires sequence argument'¶
Default diagnostic message.
- node_types: ClassVar[set[NodeType] | None] = {NodeType.BINARY_OPERATOR}¶
Tree-sitter node types to match. None = all nodes (discouraged).
- class rude.rules.pyflakes.PercentFormatUnsupportedCharacter[source]¶
Bases:
RuleF509: % format has unsupported format character.
Rationale: Using an unsupported conversion character causes a
ValueErrorat runtime.Example:
# Bad "%z" % x # F509 - z is not a valid format character # Good "%s" % x
- message: ClassVar[str] = "percent format has unsupported format character '{char}'"¶
Default diagnostic message.
- node_types: ClassVar[set[NodeType] | None] = {NodeType.BINARY_OPERATOR}¶
Tree-sitter node types to match. None = all nodes (discouraged).
- class rude.rules.pyflakes.RaiseNotImplemented[source]¶
Bases:
RuleF901: 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
- message: ClassVar[str] = 'raise NotImplemented should be raise NotImplementedError'¶
Default diagnostic message.
- node_types: ClassVar[set[NodeType] | None] = {NodeType.RAISE_STATEMENT}¶
Tree-sitter node types to match. None = all nodes (discouraged).
- class rude.rules.pyflakes.RedefinedWhileUnused[source]¶
Bases:
RuleF811: 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.
- message: ClassVar[str] = "redefinition of unused '{name}' from line {line}"¶
Default diagnostic message.
- 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.
- class rude.rules.pyflakes.ReturnOutsideFunction[source]¶
Bases:
RuleF706: return statement outside of a function.
Rationale: A
returnat module level is aSyntaxError.Example:
# Bad return 1 # F706 - not inside a function # Good def foo(): return 1
- 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.
- class rude.rules.pyflakes.StringDotFormatExtraNamedArguments[source]¶
Bases:
RuleF522: .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)
- message: ClassVar[str] = 'format string has unused named argument(s): {names}'¶
Default diagnostic message.
- node_types: ClassVar[set[NodeType] | None] = {NodeType.CALL}¶
Tree-sitter node types to match. None = all nodes (discouraged).
- class rude.rules.pyflakes.StringDotFormatExtraPositionalArguments[source]¶
Bases:
RuleF523: .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)
- message: ClassVar[str] = 'format string has {count} unused positional argument(s)'¶
Default diagnostic message.
- node_types: ClassVar[set[NodeType] | None] = {NodeType.CALL}¶
Tree-sitter node types to match. None = all nodes (discouraged).
- class rude.rules.pyflakes.StringDotFormatInvalidFormat[source]¶
Bases:
RuleF521: Invalid .format() format string.
Rationale: An invalid format string causes a
ValueErrorat runtime.Example:
# Bad "{".format() # F521 - unclosed brace "{0!z}".format() # F521 - unknown conversion # Good "{}".format(value)
- node_types: ClassVar[set[NodeType] | None] = {NodeType.CALL}¶
Tree-sitter node types to match. None = all nodes (discouraged).
- class rude.rules.pyflakes.StringDotFormatMissingArgument[source]¶
Bases:
RuleF524: .format() call is missing arguments.
Rationale: Missing arguments cause a
KeyErrororIndexErrorat runtime.Example:
# Bad "{0} {1}".format(a) # F524 - missing argument 1 "{name}".format() # F524 - missing argument 'name' # Good "{0} {1}".format(a, b)
- message: ClassVar[str] = 'format string is missing argument(s): {missing}'¶
Default diagnostic message.
- node_types: ClassVar[set[NodeType] | None] = {NodeType.CALL}¶
Tree-sitter node types to match. None = all nodes (discouraged).
- class rude.rules.pyflakes.StringDotFormatMixingAutomatic[source]¶
Bases:
RuleF525: Mixing automatic and manual field numbering in .format().
Rationale: Python does not allow mixing automatic (
{}) and manual ({0}) field numbering, raising aValueErrorat 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
- message: ClassVar[str] = 'format string mixes automatic and manual field specification'¶
Default diagnostic message.
- node_types: ClassVar[set[NodeType] | None] = {NodeType.CALL}¶
Tree-sitter node types to match. None = all nodes (discouraged).
- class rude.rules.pyflakes.TStringMissingPlaceholders[source]¶
Bases:
_PrefixStringMissingPlaceholdersF542: t-string without any placeholders.
Rationale: A t-string without placeholders adds overhead for no benefit. Remove the
tprefix to use a regular string.Example:
# Bad x = t"hello" # F542 - no placeholders # Good x = t"hello {name}" x = "hello" # plain string
- class rude.rules.pyflakes.TooManyExpressionsInStarredAssignment[source]¶
Bases:
RuleF621: 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
- message: ClassVar[str] = 'too many expressions in star-unpacking assignment'¶
Default diagnostic message.
- node_types: ClassVar[set[NodeType] | None] = {NodeType.ASSIGNMENT}¶
Tree-sitter node types to match. None = all nodes (discouraged).
- class rude.rules.pyflakes.TwoStarredExpressions[source]¶
Bases:
RuleF622: 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]
- message: ClassVar[str] = 'two or more starred expressions in assignment'¶
Default diagnostic message.
- node_types: ClassVar[set[NodeType] | None] = {NodeType.ASSIGNMENT}¶
Tree-sitter node types to match. None = all nodes (discouraged).
- class rude.rules.pyflakes.UndefinedExport[source]¶
Bases:
RuleF822: Name in __all__ is not defined.
Rationale: Listing an undefined name in
__all__causes anAttributeErrorwhen the module is imported with*.Example:
# Bad __all__ = ["foo", "bar"] # F822 - bar is not defined def foo(): pass # Good __all__ = ["foo"] def foo(): pass
- 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.
- class rude.rules.pyflakes.UndefinedLocal[source]¶
Bases:
RuleF823: Local variable referenced before assignment.
Rationale: Using a local variable before it is assigned causes an
UnboundLocalErrorat 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.
- message: ClassVar[str] = "local variable '{name}' referenced before assignment"¶
Default diagnostic message.
- 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.
- class rude.rules.pyflakes.UndefinedName[source]¶
Bases:
RuleF821: Name is not defined.
Rationale: Using an undefined name causes a
NameErrorat runtime.Example:
# Bad print(undefined_variable) # F821 # Good x = 1 print(x)
Optimized to use pre-computed unresolved names from ScopeProvider.
- 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.
- class rude.rules.pyflakes.UnusedAnnotation[source]¶
Bases:
RuleF842: 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.
- message: ClassVar[str] = "local variable '{name}' is annotated but never used"¶
Default diagnostic message.
- 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.
- class rude.rules.pyflakes.UnusedImport[source]¶
Bases:
RuleF401: 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.
- 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.
- class rude.rules.pyflakes.UnusedIndirectAssignment[source]¶
Bases:
RuleF824: Global or nonlocal declaration but name is never assigned in this scope.
Rationale: A
globalornonlocaldeclaration 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.
- message: ClassVar[str] = "local variable '{name}' is declared {kind} but never assigned"¶
Default diagnostic message.
- 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.
- class rude.rules.pyflakes.UnusedVariable[source]¶
Bases:
RuleF841: 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.
- message: ClassVar[str] = "Local variable '{name}' is assigned but never used"¶
Default diagnostic message.
- 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.
- class rude.rules.pyflakes.YieldOutsideFunction[source]¶
Bases:
RuleF704: yield or yield from outside of a function.
Rationale: A
yieldat module level is aSyntaxError.Example:
# Bad yield 1 # F704 - not inside a function # Good def gen(): yield 1
- 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.
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:
RuleE742: Ambiguous class name.
Rationale: Single-letter class names like
I,O,lare easily confused with digits in many fonts.Example:
class I: # E742 pass class Index: # OK pass
- node_types: ClassVar[set[NodeType] | None] = {NodeType.CLASS_DEFINITION}¶
Tree-sitter node types to match. None = all nodes (discouraged).
- class rude.rules.pycodestyle.AmbiguousFunctionName[source]¶
Bases:
RuleE743: Ambiguous function name.
Rationale: Single-letter function names like
I,O,lare easily confused with digits in many fonts.Example:
def l(): # E743 pass def length(): # OK pass
- node_types: ClassVar[set[NodeType] | None] = {NodeType.FUNCTION_DEFINITION}¶
Tree-sitter node types to match. None = all nodes (discouraged).
- class rude.rules.pycodestyle.AmbiguousVariableName[source]¶
Bases:
RuleE741: Ambiguous variable name.
Rationale: The names
l,O,Iare easily confused with1,0,lin many fonts.Example:
l = 1 # E741 O = 2 # E741 I = 3 # E741 length = 1 # OK
- node_types: ClassVar[set[NodeType] | None] = {NodeType.ASSIGNMENT, NodeType.FOR_STATEMENT, NodeType.WITH_STATEMENT}¶
Tree-sitter node types to match. None = all nodes (discouraged).
- class rude.rules.pycodestyle.BareExcept[source]¶
Bases:
RuleE722: Do not use bare ‘except’.
Rationale: A bare
except:catches all exceptions includingKeyboardInterruptandSystemExit, which is almost never intended.Example:
try: x = 1 except: # E722 pass try: x = 1 except Exception: # OK pass
- node_types: ClassVar[set[NodeType] | None] = {NodeType.EXCEPT_CLAUSE}¶
Tree-sitter node types to match. None = all nodes (discouraged).
- class rude.rules.pycodestyle.BlankLineAtEndOfFile[source]¶
Bases:
RuleW391: 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
- node_types: ClassVar[set[NodeType] | None] = {NodeType.MODULE}¶
Tree-sitter node types to match. None = all nodes (discouraged).
- class rude.rules.pycodestyle.BlankLineContainsWhitespace[source]¶
Bases:
LineRuleW293: 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
- 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 infocomment_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:
- check_line_info(lineno, info, ctx)[source]¶
Fast path using pre-computed line metadata from Rust.
Override this when
uses_line_infos = True. Theinfoargument is aLineInfostruct (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:
lineno (
int)info (
LineInfo)ctx (
FileContext)
- Return type:
- class rude.rules.pycodestyle.BlankLinesAfterDecorator[source]¶
Bases:
RuleE304: 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
- node_types: ClassVar[set[NodeType] | None] = {NodeType.DECORATED_DEFINITION}¶
Tree-sitter node types to match. None = all nodes (discouraged).
- class rude.rules.pycodestyle.BlockCommentShouldStartWithSpace[source]¶
Bases:
LineRuleE265: 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)
- 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. Theinfoargument is aLineInfostruct (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:
lineno (
int)info (
LineInfo)ctx (
FileContext)
- Return type:
- 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 infocomment_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:
- class rude.rules.pycodestyle.ComparisonToNone[source]¶
Bases:
RuleE711: Comparison to None should use ‘is’ or ‘is not’.
Rationale:
Noneis 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
- 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).
- class rude.rules.pycodestyle.ComparisonToTrueFalse[source]¶
Bases:
RuleE712: Comparison to True/False should use ‘if cond:’ or ‘if not cond:’.
Rationale: Comparing to
True/Falsewith==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
- 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).
- class rude.rules.pycodestyle.ExpectedOneBlankLine[source]¶
Bases:
RuleE301: 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
- node_types: ClassVar[set[NodeType] | None] = {NodeType.FUNCTION_DEFINITION}¶
Tree-sitter node types to match. None = all nodes (discouraged).
- class rude.rules.pycodestyle.ExpectedOneBlankLineBeforeNestedDef[source]¶
Bases:
RuleE306: 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
- 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).
- class rude.rules.pycodestyle.ExpectedTwoBlankLines[source]¶
Bases:
RuleE302: 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
- node_types: ClassVar[set[NodeType] | None] = {NodeType.CLASS_DEFINITION, NodeType.FUNCTION_DEFINITION}¶
Tree-sitter node types to match. None = all nodes (discouraged).
- class rude.rules.pycodestyle.ExpectedTwoBlankLinesAfterClassOrFunction[source]¶
Bases:
RuleE305: 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
- 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).
- class rude.rules.pycodestyle.IndentationContainsMixedSpacesAndTabs[source]¶
Bases:
LineRuleE101: Indentation contains mixed spaces and tabs.
Rationale: Mixing tabs and spaces makes indentation ambiguous and can cause
TabErrorin Python 3.Example:
def foo(): x = 1 # E101 - tab after spaces def foo(): x = 1 # OK - spaces only
- 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 infocomment_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:
- check_line_info(lineno, info, ctx)[source]¶
Fast path using pre-computed line metadata from Rust.
Override this when
uses_line_infos = True. Theinfoargument is aLineInfostruct (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:
lineno (
int)info (
LineInfo)ctx (
FileContext)
- Return type:
- class rude.rules.pycodestyle.IndentationContainsTabs[source]¶
Bases:
LineRuleW191: 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
- 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 infocomment_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:
- check_line_info(lineno, info, ctx)[source]¶
Fast path using pre-computed line metadata from Rust.
Override this when
uses_line_infos = True. Theinfoargument is aLineInfostruct (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:
lineno (
int)info (
LineInfo)ctx (
FileContext)
- Return type:
- class rude.rules.pycodestyle.IndentationNotMultipleOfFour[source]¶
Bases:
LineRuleE111: 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
- 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.
- 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 infocomment_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:
- check_line_info(lineno, info, ctx)[source]¶
Fast path using pre-computed line metadata from Rust.
Override this when
uses_line_infos = True. Theinfoargument is aLineInfostruct (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:
lineno (
int)info (
LineInfo)ctx (
FileContext)
- Return type:
- class rude.rules.pycodestyle.InlineCommentShouldStartWithSpace[source]¶
Bases:
LineRuleE262: 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
- 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. Theinfoargument is aLineInfostruct (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:
lineno (
int)info (
LineInfo)ctx (
FileContext)
- Return type:
- 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 infocomment_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:
- class rude.rules.pycodestyle.InvalidEscapeSequence[source]¶
Bases:
RuleW605: Invalid escape sequence.
Rationale: Invalid escape sequences raise
DeprecationWarningin Python 3.12+ and will becomeSyntaxErrorin a future version.Example:
x = "\d+" # W605 - invalid escape sequence x = r"\d+" # OK - raw string x = "\\d+" # OK - escaped backslash
- node_types: ClassVar[set[NodeType] | None] = {NodeType.STRING}¶
Tree-sitter node types to match. None = all nodes (discouraged).
- class rude.rules.pycodestyle.LambdaAssignment[source]¶
Bases:
RuleE731: Do not assign a lambda expression, use a def.
Rationale: Assigning a lambda defeats its purpose as an anonymous function. A
defprovides a name for tracebacks and is clearer.Example:
f = lambda x: x + 1 # E731 def f(x): # OK return x + 1
- 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).
- class rude.rules.pycodestyle.LineTooLong[source]¶
Bases:
RuleE501: 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
- 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).
- class rude.rules.pycodestyle.MissingWhitespaceAfterComma[source]¶
Bases:
RuleE231: 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
- 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).
- class rude.rules.pycodestyle.MissingWhitespaceAfterKeyword[source]¶
Bases:
RuleE275: 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)
- node_types: ClassVar[set[NodeType] | None] = {NodeType.MODULE}¶
Tree-sitter node types to match. None = all nodes (discouraged).
- class rude.rules.pycodestyle.MissingWhitespaceAroundArithmeticOperator[source]¶
Bases:
RuleE226: 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
- 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).
- class rude.rules.pycodestyle.MissingWhitespaceAroundBitwiseOperator[source]¶
Bases:
RuleE227: 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
- 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).
- class rude.rules.pycodestyle.MissingWhitespaceAroundModuloOperator[source]¶
Bases:
RuleE228: 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
- node_types: ClassVar[set[NodeType] | None] = {NodeType.BINARY_OPERATOR}¶
Tree-sitter node types to match. None = all nodes (discouraged).
- class rude.rules.pycodestyle.MissingWhitespaceAroundOperator[source]¶
Bases:
RuleE225: 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
- 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).
- class rude.rules.pycodestyle.ModuleLevelImportNotAtTop[source]¶
Bases:
RuleE402: 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
- node_types: ClassVar[set[NodeType] | None] = {NodeType.IMPORT_FROM_STATEMENT, NodeType.IMPORT_STATEMENT}¶
Tree-sitter node types to match. None = all nodes (discouraged).
- class rude.rules.pycodestyle.MultipleImportsOnOneLine[source]¶
Bases:
RuleE401: 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
- node_types: ClassVar[set[NodeType] | None] = {NodeType.IMPORT_STATEMENT}¶
Tree-sitter node types to match. None = all nodes (discouraged).
- class rude.rules.pycodestyle.MultipleSpacesAfterComma[source]¶
Bases:
LineRuleE241: 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
- 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. Theinfoargument is aLineInfostruct (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:
lineno (
int)info (
LineInfo)ctx (
FileContext)
- Return type:
- 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 infocomment_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:
- class rude.rules.pycodestyle.MultipleSpacesAfterKeyword[source]¶
Bases:
LineRuleE271: Multiple spaces after keyword.
Rationale: PEP 8 requires exactly one space after keywords.
Example:
if x: # E271 if x: # OK
- 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. Theinfoargument is aLineInfostruct (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:
lineno (
int)info (
LineInfo)ctx (
FileContext)
- Return type:
- 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 infocomment_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:
- class rude.rules.pycodestyle.MultipleSpacesAfterOperator[source]¶
Bases:
LineRuleE222: Multiple spaces after operator.
Rationale: PEP 8 requires exactly one space around operators.
Example:
a = 4 + 5 # E222 a = 4 + 5 # OK
- 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. Theinfoargument is aLineInfostruct (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:
lineno (
int)info (
LineInfo)ctx (
FileContext)
- Return type:
- 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 infocomment_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:
- class rude.rules.pycodestyle.MultipleSpacesBeforeKeyword[source]¶
Bases:
LineRuleE272: Multiple spaces before keyword.
Rationale: PEP 8 requires exactly one space before keywords.
Example:
True and False # E272 True and False # OK
- 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. Theinfoargument is aLineInfostruct (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:
lineno (
int)info (
LineInfo)ctx (
FileContext)
- Return type:
- 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 infocomment_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:
- class rude.rules.pycodestyle.MultipleSpacesBeforeOperator[source]¶
Bases:
LineRuleE221: 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
- 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. Theinfoargument is aLineInfostruct (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:
lineno (
int)info (
LineInfo)ctx (
FileContext)
- Return type:
- 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 infocomment_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:
- class rude.rules.pycodestyle.MultipleStatementsOnOneLineColon[source]¶
Bases:
RuleE701: 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
- 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).
- class rude.rules.pycodestyle.MultipleStatementsOnOneLineDef[source]¶
Bases:
RuleE704: 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
- node_types: ClassVar[set[NodeType] | None] = {NodeType.FUNCTION_DEFINITION}¶
Tree-sitter node types to match. None = all nodes (discouraged).
- class rude.rules.pycodestyle.MultipleStatementsOnOneLineSemicolon[source]¶
Bases:
RuleE702: 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
- 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).
- class rude.rules.pycodestyle.NoNewlineAtEndOfFile[source]¶
Bases:
RuleW292: 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
- node_types: ClassVar[set[NodeType] | None] = {NodeType.MODULE}¶
Tree-sitter node types to match. None = all nodes (discouraged).
- class rude.rules.pycodestyle.NotInTest[source]¶
Bases:
RuleE713: Test for membership should be ‘not in’.
Rationale:
not x in yis harder to read than the idiomaticx not in y.Example:
not x in y # E713 - use 'x not in y' x not in y # OK
- node_types: ClassVar[set[NodeType] | None] = {NodeType.NOT_OPERATOR}¶
Tree-sitter node types to match. None = all nodes (discouraged).
- class rude.rules.pycodestyle.NotIsTest[source]¶
Bases:
RuleE714: Test for object identity should be ‘is not’.
Rationale:
not x is yis harder to read than the idiomaticx is not y.Example:
not x is y # E714 - use 'x is not y' x is not y # OK
- node_types: ClassVar[set[NodeType] | None] = {NodeType.NOT_OPERATOR}¶
Tree-sitter node types to match. None = all nodes (discouraged).
- class rude.rules.pycodestyle.OverIndented[source]¶
Bases:
RuleE117: 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
- node_types: ClassVar[set[NodeType] | None] = {NodeType.BLOCK}¶
Tree-sitter node types to match. None = all nodes (discouraged).
- class rude.rules.pycodestyle.StatementEndsWithSemicolon[source]¶
Bases:
RuleE703: 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
- node_types: ClassVar[set[NodeType] | None] = {NodeType.MODULE}¶
Tree-sitter node types to match. None = all nodes (discouraged).
- class rude.rules.pycodestyle.TabAfterComma[source]¶
Bases:
LineRuleE242: 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
- 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. Theinfoargument is aLineInfostruct (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:
lineno (
int)info (
LineInfo)ctx (
FileContext)
- Return type:
- 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 infocomment_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:
- class rude.rules.pycodestyle.TabAfterKeyword[source]¶
Bases:
LineRuleE273: Tab after keyword.
Rationale: PEP 8 requires spaces, not tabs, after keywords.
Example:
if\tx: # E273 if x: # OK
- 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. Theinfoargument is aLineInfostruct (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:
lineno (
int)info (
LineInfo)ctx (
FileContext)
- Return type:
- 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 infocomment_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:
- class rude.rules.pycodestyle.TabAfterOperator[source]¶
Bases:
LineRuleE224: Tab after operator.
Rationale: PEP 8 requires spaces, not tabs, around operators.
Example:
a = 4 +\t5 # E224 a = 4 + 5 # OK
- 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. Theinfoargument is aLineInfostruct (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:
lineno (
int)info (
LineInfo)ctx (
FileContext)
- Return type:
- 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 infocomment_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:
- class rude.rules.pycodestyle.TabBeforeKeyword[source]¶
Bases:
LineRuleE274: Tab before keyword.
Rationale: PEP 8 requires spaces, not tabs, before keywords.
Example:
True\tand False # E274 True and False # OK
- 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. Theinfoargument is aLineInfostruct (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:
lineno (
int)info (
LineInfo)ctx (
FileContext)
- Return type:
- 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 infocomment_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:
- class rude.rules.pycodestyle.TabBeforeOperator[source]¶
Bases:
LineRuleE223: Tab before operator.
Rationale: PEP 8 requires spaces, not tabs, around operators.
Example:
a = 4\t+ 5 # E223 a = 4 + 5 # OK
- 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. Theinfoargument is aLineInfostruct (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:
lineno (
int)info (
LineInfo)ctx (
FileContext)
- Return type:
- 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 infocomment_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:
- class rude.rules.pycodestyle.TooManyBlankLines[source]¶
Bases:
RuleE303: 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
- node_types: ClassVar[set[NodeType] | None] = {NodeType.MODULE}¶
Tree-sitter node types to match. None = all nodes (discouraged).
- class rude.rules.pycodestyle.TooManyHashesForBlockComment[source]¶
Bases:
LineRuleE266: 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)
- 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. Theinfoargument is aLineInfostruct (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:
lineno (
int)info (
LineInfo)ctx (
FileContext)
- Return type:
- 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 infocomment_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:
- class rude.rules.pycodestyle.TrailingWhitespace[source]¶
Bases:
LineRuleW291: 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
- 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 infocomment_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:
- check_line_info(lineno, info, ctx)[source]¶
Fast path using pre-computed line metadata from Rust.
Override this when
uses_line_infos = True. Theinfoargument is aLineInfostruct (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:
lineno (
int)info (
LineInfo)ctx (
FileContext)
- Return type:
- class rude.rules.pycodestyle.TwoSpacesBeforeInlineComment[source]¶
Bases:
LineRuleE261: 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
- 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. Theinfoargument is aLineInfostruct (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:
lineno (
int)info (
LineInfo)ctx (
FileContext)
- Return type:
- 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 infocomment_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:
- class rude.rules.pycodestyle.TypeComparison[source]¶
Bases:
RuleE721: Do not compare types, use isinstance().
Rationale:
isinstance()correctly handles subclasses, whiletype()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
- node_types: ClassVar[set[NodeType] | None] = {NodeType.COMPARISON_OPERATOR}¶
Tree-sitter node types to match. None = all nodes (discouraged).
- class rude.rules.pycodestyle.UnexpectedSpacesAroundKeywordEquals[source]¶
Bases:
RuleE251: 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
- 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).
- class rude.rules.pycodestyle.WhitespaceAfterOpenBracket[source]¶
Bases:
RuleE201: Whitespace after ‘(’, ‘[’, or ‘{‘.
Rationale: PEP 8 requires no whitespace immediately after opening brackets.
Example:
spam( ham) # E201 spam(ham) # OK
- 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).
- class rude.rules.pycodestyle.WhitespaceBeforeCloseBracket[source]¶
Bases:
RuleE202: Whitespace before ‘)’, ‘]’, or ‘}’.
Rationale: PEP 8 requires no whitespace immediately before closing brackets.
Example:
spam(ham ) # E202 spam(ham) # OK
- 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).
- class rude.rules.pycodestyle.WhitespaceBeforeColon[source]¶
Bases:
RuleE203: Whitespace before ‘:’ or ‘,’.
Rationale: PEP 8 requires no whitespace immediately before colons, commas, or semicolons.
Example:
spam[1 :] # E203 spam[1:] # OK
- 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).
- class rude.rules.pycodestyle.WhitespaceBeforeParameters[source]¶
Bases:
RuleE211: 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
- node_types: ClassVar[set[NodeType] | None] = {NodeType.CALL}¶
Tree-sitter node types to match. None = all nodes (discouraged).
McCabe¶
McCabe complexity rules for Rude.
C9xx: Complexity
- class rude.rules.mccabe.FunctionTooComplex[source]¶
Bases:
RuleC901: 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
- node_types: ClassVar[set[NodeType] | None] = {NodeType.FUNCTION_DEFINITION}¶
Tree-sitter node types to match. None = all nodes (discouraged).
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.