MCPcopy Create free account
hub / github.com/FastLED/FastLED / TryExceptVisitor

Class TryExceptVisitor

ci/lint_python/keyboard_interrupt_checker.py:83–177  ·  view source on GitHub ↗

AST visitor to check try-except blocks for KeyboardInterrupt handling.

Source from the content-addressed store, hash-verified

81
82
83class TryExceptVisitor(ast.NodeVisitor):
84 """AST visitor to check try-except blocks for KeyboardInterrupt handling."""
85
86 def __init__(self, source_lines: list[str] | None = None) -> None:
87 self.violations: list[Violation] = []
88 self._source_lines: list[str] = source_lines or []
89
90 def visit_Try(self, node: ast.Try) -> None: # noqa: N802
91 catches_broad_exception = False
92 has_keyboard_interrupt_handler = False
93 keyboard_interrupt_handlers: list[ast.ExceptHandler] = []
94
95 for handler in node.handlers:
96 if handler.type is None:
97 # bare except: catches everything
98 catches_broad_exception = True
99 elif isinstance(handler.type, ast.Name):
100 if handler.type.id in ("Exception", "BaseException"):
101 catches_broad_exception = True
102 elif handler.type.id == "KeyboardInterrupt":
103 has_keyboard_interrupt_handler = True
104 keyboard_interrupt_handlers.append(handler)
105 elif isinstance(handler.type, ast.Tuple):
106 for exc_type in handler.type.elts:
107 if isinstance(exc_type, ast.Name):
108 if exc_type.id in ("Exception", "BaseException"):
109 catches_broad_exception = True
110 elif exc_type.id == "KeyboardInterrupt":
111 has_keyboard_interrupt_handler = True
112 keyboard_interrupt_handlers.append(handler)
113
114 if catches_broad_exception and not has_keyboard_interrupt_handler:
115 if not _is_suppressed(self._source_lines, node.lineno, "KBI001"):
116 self.violations.append(
117 Violation(
118 line=node.lineno,
119 col=node.col_offset,
120 code="KBI001",
121 message=(
122 "Try-except catches Exception/BaseException without KeyboardInterrupt handler. "
123 "Add: except KeyboardInterrupt as ki: handle_keyboard_interrupt(ki)"
124 ),
125 )
126 )
127
128 for kbi_handler in keyboard_interrupt_handlers:
129 if not _handler_calls_interrupt_main(kbi_handler):
130 if not _is_suppressed(self._source_lines, kbi_handler.lineno, "KBI002"):
131 self.violations.append(
132 Violation(
133 line=kbi_handler.lineno,
134 col=kbi_handler.col_offset,
135 code="KBI002",
136 message=(
137 "KeyboardInterrupt handler must call _thread.interrupt_main() "
138 "or use handle_keyboard_interrupt(ki). "
139 "Add: import _thread; _thread.interrupt_main()"
140 ),

Callers 1

check_fileFunction · 0.85

Calls

no outgoing calls

Tested by

no test coverage detected