fbuild 1.2.8__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fbuild/__init__.py +390 -0
- fbuild/assets/example.txt +1 -0
- fbuild/build/__init__.py +117 -0
- fbuild/build/archive_creator.py +186 -0
- fbuild/build/binary_generator.py +444 -0
- fbuild/build/build_component_factory.py +131 -0
- fbuild/build/build_info_generator.py +624 -0
- fbuild/build/build_state.py +325 -0
- fbuild/build/build_utils.py +93 -0
- fbuild/build/compilation_executor.py +422 -0
- fbuild/build/compiler.py +165 -0
- fbuild/build/compiler_avr.py +574 -0
- fbuild/build/configurable_compiler.py +664 -0
- fbuild/build/configurable_linker.py +637 -0
- fbuild/build/flag_builder.py +214 -0
- fbuild/build/library_dependency_processor.py +185 -0
- fbuild/build/linker.py +708 -0
- fbuild/build/orchestrator.py +67 -0
- fbuild/build/orchestrator_avr.py +651 -0
- fbuild/build/orchestrator_esp32.py +878 -0
- fbuild/build/orchestrator_rp2040.py +719 -0
- fbuild/build/orchestrator_stm32.py +696 -0
- fbuild/build/orchestrator_teensy.py +580 -0
- fbuild/build/source_compilation_orchestrator.py +218 -0
- fbuild/build/source_scanner.py +516 -0
- fbuild/cli.py +717 -0
- fbuild/cli_utils.py +314 -0
- fbuild/config/__init__.py +16 -0
- fbuild/config/board_config.py +542 -0
- fbuild/config/board_loader.py +92 -0
- fbuild/config/ini_parser.py +369 -0
- fbuild/config/mcu_specs.py +88 -0
- fbuild/daemon/__init__.py +42 -0
- fbuild/daemon/async_client.py +531 -0
- fbuild/daemon/client.py +1505 -0
- fbuild/daemon/compilation_queue.py +293 -0
- fbuild/daemon/configuration_lock.py +865 -0
- fbuild/daemon/daemon.py +585 -0
- fbuild/daemon/daemon_context.py +293 -0
- fbuild/daemon/error_collector.py +263 -0
- fbuild/daemon/file_cache.py +332 -0
- fbuild/daemon/firmware_ledger.py +546 -0
- fbuild/daemon/lock_manager.py +508 -0
- fbuild/daemon/logging_utils.py +149 -0
- fbuild/daemon/messages.py +957 -0
- fbuild/daemon/operation_registry.py +288 -0
- fbuild/daemon/port_state_manager.py +249 -0
- fbuild/daemon/process_tracker.py +366 -0
- fbuild/daemon/processors/__init__.py +18 -0
- fbuild/daemon/processors/build_processor.py +248 -0
- fbuild/daemon/processors/deploy_processor.py +664 -0
- fbuild/daemon/processors/install_deps_processor.py +431 -0
- fbuild/daemon/processors/locking_processor.py +777 -0
- fbuild/daemon/processors/monitor_processor.py +285 -0
- fbuild/daemon/request_processor.py +457 -0
- fbuild/daemon/shared_serial.py +819 -0
- fbuild/daemon/status_manager.py +238 -0
- fbuild/daemon/subprocess_manager.py +316 -0
- fbuild/deploy/__init__.py +21 -0
- fbuild/deploy/deployer.py +67 -0
- fbuild/deploy/deployer_esp32.py +310 -0
- fbuild/deploy/docker_utils.py +315 -0
- fbuild/deploy/monitor.py +519 -0
- fbuild/deploy/qemu_runner.py +603 -0
- fbuild/interrupt_utils.py +34 -0
- fbuild/ledger/__init__.py +52 -0
- fbuild/ledger/board_ledger.py +560 -0
- fbuild/output.py +352 -0
- fbuild/packages/__init__.py +66 -0
- fbuild/packages/archive_utils.py +1098 -0
- fbuild/packages/arduino_core.py +412 -0
- fbuild/packages/cache.py +256 -0
- fbuild/packages/concurrent_manager.py +510 -0
- fbuild/packages/downloader.py +518 -0
- fbuild/packages/fingerprint.py +423 -0
- fbuild/packages/framework_esp32.py +538 -0
- fbuild/packages/framework_rp2040.py +349 -0
- fbuild/packages/framework_stm32.py +459 -0
- fbuild/packages/framework_teensy.py +346 -0
- fbuild/packages/github_utils.py +96 -0
- fbuild/packages/header_trampoline_cache.py +394 -0
- fbuild/packages/library_compiler.py +203 -0
- fbuild/packages/library_manager.py +549 -0
- fbuild/packages/library_manager_esp32.py +725 -0
- fbuild/packages/package.py +163 -0
- fbuild/packages/platform_esp32.py +383 -0
- fbuild/packages/platform_rp2040.py +400 -0
- fbuild/packages/platform_stm32.py +581 -0
- fbuild/packages/platform_teensy.py +312 -0
- fbuild/packages/platform_utils.py +131 -0
- fbuild/packages/platformio_registry.py +369 -0
- fbuild/packages/sdk_utils.py +231 -0
- fbuild/packages/toolchain.py +436 -0
- fbuild/packages/toolchain_binaries.py +196 -0
- fbuild/packages/toolchain_esp32.py +489 -0
- fbuild/packages/toolchain_metadata.py +185 -0
- fbuild/packages/toolchain_rp2040.py +436 -0
- fbuild/packages/toolchain_stm32.py +417 -0
- fbuild/packages/toolchain_teensy.py +404 -0
- fbuild/platform_configs/esp32.json +150 -0
- fbuild/platform_configs/esp32c2.json +144 -0
- fbuild/platform_configs/esp32c3.json +143 -0
- fbuild/platform_configs/esp32c5.json +151 -0
- fbuild/platform_configs/esp32c6.json +151 -0
- fbuild/platform_configs/esp32p4.json +149 -0
- fbuild/platform_configs/esp32s3.json +151 -0
- fbuild/platform_configs/imxrt1062.json +56 -0
- fbuild/platform_configs/rp2040.json +70 -0
- fbuild/platform_configs/rp2350.json +76 -0
- fbuild/platform_configs/stm32f1.json +59 -0
- fbuild/platform_configs/stm32f4.json +63 -0
- fbuild/py.typed +0 -0
- fbuild-1.2.8.dist-info/METADATA +468 -0
- fbuild-1.2.8.dist-info/RECORD +121 -0
- fbuild-1.2.8.dist-info/WHEEL +5 -0
- fbuild-1.2.8.dist-info/entry_points.txt +5 -0
- fbuild-1.2.8.dist-info/licenses/LICENSE +21 -0
- fbuild-1.2.8.dist-info/top_level.txt +2 -0
- fbuild_lint/__init__.py +0 -0
- fbuild_lint/ruff_plugins/__init__.py +0 -0
- fbuild_lint/ruff_plugins/keyboard_interrupt_checker.py +158 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
"""Flake8 plugin to check for proper KeyboardInterrupt handling.
|
|
2
|
+
|
|
3
|
+
This plugin ensures that try-except blocks that catch broad exceptions
|
|
4
|
+
(like Exception or BaseException) also properly handle KeyboardInterrupt.
|
|
5
|
+
|
|
6
|
+
Error Codes:
|
|
7
|
+
KBI001: Try-except catches Exception/BaseException without KeyboardInterrupt handler
|
|
8
|
+
KBI002: KeyboardInterrupt handler must call _thread.interrupt_main() or handle_keyboard_interrupt_properly()
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import ast
|
|
12
|
+
from typing import Any, Generator, Tuple, Type
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class KeyboardInterruptChecker:
|
|
16
|
+
"""Flake8 plugin to check for proper KeyboardInterrupt handling."""
|
|
17
|
+
|
|
18
|
+
name = "keyboard-interrupt-checker"
|
|
19
|
+
version = "1.0.0"
|
|
20
|
+
|
|
21
|
+
def __init__(self, tree: ast.AST) -> None:
|
|
22
|
+
"""Initialize the checker with an AST tree.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
tree: The AST tree to check
|
|
26
|
+
"""
|
|
27
|
+
self._tree = tree
|
|
28
|
+
|
|
29
|
+
def run(self) -> Generator[Tuple[int, int, str, Type[Any]], None, None]:
|
|
30
|
+
"""Run the checker on the AST tree.
|
|
31
|
+
|
|
32
|
+
Yields:
|
|
33
|
+
Tuple of (line_number, column, message, type)
|
|
34
|
+
"""
|
|
35
|
+
visitor = TryExceptVisitor()
|
|
36
|
+
visitor.visit(self._tree)
|
|
37
|
+
|
|
38
|
+
for line, col, msg in visitor.errors:
|
|
39
|
+
yield (line, col, msg, type(self))
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class TryExceptVisitor(ast.NodeVisitor):
|
|
43
|
+
"""AST visitor to check try-except blocks for KeyboardInterrupt handling."""
|
|
44
|
+
|
|
45
|
+
def __init__(self) -> None:
|
|
46
|
+
"""Initialize the visitor."""
|
|
47
|
+
self.errors: list[Tuple[int, int, str]] = []
|
|
48
|
+
|
|
49
|
+
def visit_Try(self, node: ast.Try) -> None:
|
|
50
|
+
"""Visit a Try node and check exception handlers.
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
node: The Try node to check
|
|
54
|
+
"""
|
|
55
|
+
# Check if any handler catches Exception or BaseException
|
|
56
|
+
catches_broad_exception = False
|
|
57
|
+
has_keyboard_interrupt_handler = False
|
|
58
|
+
keyboard_interrupt_handlers = []
|
|
59
|
+
|
|
60
|
+
for handler in node.handlers:
|
|
61
|
+
if handler.type is None:
|
|
62
|
+
# bare except: catches everything
|
|
63
|
+
catches_broad_exception = True
|
|
64
|
+
elif isinstance(handler.type, ast.Name):
|
|
65
|
+
if handler.type.id in ("Exception", "BaseException"):
|
|
66
|
+
catches_broad_exception = True
|
|
67
|
+
elif handler.type.id == "KeyboardInterrupt":
|
|
68
|
+
has_keyboard_interrupt_handler = True
|
|
69
|
+
keyboard_interrupt_handlers.append(handler)
|
|
70
|
+
elif isinstance(handler.type, ast.Tuple):
|
|
71
|
+
# Check if tuple contains Exception or BaseException
|
|
72
|
+
for exc_type in handler.type.elts:
|
|
73
|
+
if isinstance(exc_type, ast.Name):
|
|
74
|
+
if exc_type.id in ("Exception", "BaseException"):
|
|
75
|
+
catches_broad_exception = True
|
|
76
|
+
elif exc_type.id == "KeyboardInterrupt":
|
|
77
|
+
has_keyboard_interrupt_handler = True
|
|
78
|
+
keyboard_interrupt_handlers.append(handler)
|
|
79
|
+
|
|
80
|
+
# If we catch broad exceptions without KeyboardInterrupt handler, that's an error
|
|
81
|
+
if catches_broad_exception and not has_keyboard_interrupt_handler:
|
|
82
|
+
self.errors.append(
|
|
83
|
+
(
|
|
84
|
+
node.lineno,
|
|
85
|
+
node.col_offset,
|
|
86
|
+
(
|
|
87
|
+
"KBI001 Try-except catches Exception/BaseException without KeyboardInterrupt handler. "
|
|
88
|
+
"Add: except KeyboardInterrupt as ke: handle_keyboard_interrupt_properly(ke)"
|
|
89
|
+
),
|
|
90
|
+
)
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
# Check all KeyboardInterrupt handlers to ensure they call _thread.interrupt_main()
|
|
94
|
+
for keyboard_interrupt_handler in keyboard_interrupt_handlers:
|
|
95
|
+
if not self._handler_calls_interrupt_main(keyboard_interrupt_handler):
|
|
96
|
+
self.errors.append(
|
|
97
|
+
(
|
|
98
|
+
keyboard_interrupt_handler.lineno,
|
|
99
|
+
keyboard_interrupt_handler.col_offset,
|
|
100
|
+
(
|
|
101
|
+
"KBI002 KeyboardInterrupt handler must call _thread.interrupt_main() "
|
|
102
|
+
"or use handle_keyboard_interrupt_properly(). "
|
|
103
|
+
"Add: import _thread; _thread.interrupt_main()"
|
|
104
|
+
),
|
|
105
|
+
)
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
# Continue visiting child nodes
|
|
109
|
+
self.generic_visit(node)
|
|
110
|
+
|
|
111
|
+
def _handler_calls_interrupt_main(self, handler: ast.ExceptHandler) -> bool:
|
|
112
|
+
"""Check if a KeyboardInterrupt handler properly calls _thread.interrupt_main().
|
|
113
|
+
|
|
114
|
+
Args:
|
|
115
|
+
handler: The exception handler to check
|
|
116
|
+
|
|
117
|
+
Returns:
|
|
118
|
+
True if the handler calls _thread.interrupt_main(), handle_keyboard_interrupt_properly(),
|
|
119
|
+
sys.exit(), ErrorFormatter.handle_keyboard_interrupt(), or re-raises the exception
|
|
120
|
+
"""
|
|
121
|
+
# Check for re-raise (bare raise statement)
|
|
122
|
+
for node in ast.walk(handler):
|
|
123
|
+
if isinstance(node, ast.Raise):
|
|
124
|
+
# Bare raise (re-raise) is allowed
|
|
125
|
+
if node.exc is None:
|
|
126
|
+
return True
|
|
127
|
+
|
|
128
|
+
# Check for calls to _thread.interrupt_main(), handle_keyboard_interrupt_properly(), or sys.exit()
|
|
129
|
+
for node in ast.walk(handler):
|
|
130
|
+
if isinstance(node, ast.Call):
|
|
131
|
+
# Check for _thread.interrupt_main()
|
|
132
|
+
if isinstance(node.func, ast.Attribute):
|
|
133
|
+
if (
|
|
134
|
+
isinstance(node.func.value, ast.Name)
|
|
135
|
+
and node.func.value.id == "_thread"
|
|
136
|
+
and node.func.attr == "interrupt_main"
|
|
137
|
+
):
|
|
138
|
+
return True
|
|
139
|
+
# Check for sys.exit()
|
|
140
|
+
if (
|
|
141
|
+
isinstance(node.func.value, ast.Name)
|
|
142
|
+
and node.func.value.id == "sys"
|
|
143
|
+
and node.func.attr == "exit"
|
|
144
|
+
):
|
|
145
|
+
return True
|
|
146
|
+
# Check for ErrorFormatter.handle_keyboard_interrupt() or similar
|
|
147
|
+
if node.func.attr == "handle_keyboard_interrupt":
|
|
148
|
+
return True
|
|
149
|
+
|
|
150
|
+
# Check for handle_keyboard_interrupt_properly()
|
|
151
|
+
if isinstance(node.func, ast.Name):
|
|
152
|
+
if node.func.id == "handle_keyboard_interrupt_properly":
|
|
153
|
+
return True
|
|
154
|
+
# Check for handle_keyboard_interrupt()
|
|
155
|
+
if node.func.id == "handle_keyboard_interrupt":
|
|
156
|
+
return True
|
|
157
|
+
|
|
158
|
+
return False
|