fbuild 1.1.0__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.
Potentially problematic release.
This version of fbuild might be problematic. Click here for more details.
- fbuild/__init__.py +0 -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_state.py +325 -0
- fbuild/build/build_utils.py +98 -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 +612 -0
- fbuild/build/configurable_linker.py +637 -0
- fbuild/build/flag_builder.py +186 -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 +656 -0
- fbuild/build/orchestrator_esp32.py +797 -0
- fbuild/build/orchestrator_teensy.py +543 -0
- fbuild/build/source_compilation_orchestrator.py +220 -0
- fbuild/build/source_scanner.py +516 -0
- fbuild/cli.py +566 -0
- fbuild/cli_utils.py +312 -0
- fbuild/config/__init__.py +16 -0
- fbuild/config/board_config.py +457 -0
- fbuild/config/board_loader.py +92 -0
- fbuild/config/ini_parser.py +209 -0
- fbuild/config/mcu_specs.py +88 -0
- fbuild/daemon/__init__.py +34 -0
- fbuild/daemon/client.py +929 -0
- fbuild/daemon/compilation_queue.py +293 -0
- fbuild/daemon/daemon.py +474 -0
- fbuild/daemon/daemon_context.py +196 -0
- fbuild/daemon/error_collector.py +263 -0
- fbuild/daemon/file_cache.py +332 -0
- fbuild/daemon/lock_manager.py +270 -0
- fbuild/daemon/logging_utils.py +149 -0
- fbuild/daemon/messages.py +301 -0
- fbuild/daemon/operation_registry.py +288 -0
- fbuild/daemon/process_tracker.py +366 -0
- fbuild/daemon/processors/__init__.py +12 -0
- fbuild/daemon/processors/build_processor.py +157 -0
- fbuild/daemon/processors/deploy_processor.py +327 -0
- fbuild/daemon/processors/monitor_processor.py +146 -0
- fbuild/daemon/request_processor.py +401 -0
- fbuild/daemon/status_manager.py +216 -0
- fbuild/daemon/subprocess_manager.py +316 -0
- fbuild/deploy/__init__.py +17 -0
- fbuild/deploy/deployer.py +67 -0
- fbuild/deploy/deployer_esp32.py +314 -0
- fbuild/deploy/monitor.py +495 -0
- fbuild/interrupt_utils.py +34 -0
- fbuild/packages/__init__.py +53 -0
- fbuild/packages/archive_utils.py +1098 -0
- fbuild/packages/arduino_core.py +412 -0
- fbuild/packages/cache.py +249 -0
- fbuild/packages/downloader.py +366 -0
- fbuild/packages/framework_esp32.py +538 -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 +413 -0
- fbuild/packages/package.py +163 -0
- fbuild/packages/platform_esp32.py +383 -0
- fbuild/packages/platform_teensy.py +312 -0
- fbuild/packages/platform_utils.py +131 -0
- fbuild/packages/platformio_registry.py +325 -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 +484 -0
- fbuild/packages/toolchain_metadata.py +185 -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-1.1.0.dist-info/METADATA +447 -0
- fbuild-1.1.0.dist-info/RECORD +93 -0
- fbuild-1.1.0.dist-info/WHEEL +5 -0
- fbuild-1.1.0.dist-info/entry_points.txt +5 -0
- fbuild-1.1.0.dist-info/licenses/LICENSE +21 -0
- fbuild-1.1.0.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,93 @@
|
|
|
1
|
+
fbuild/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
fbuild/cli.py,sha256=U74ITXQv2fCTU8FcARWEbuQ00DhOVxOgcuZNadJXKEg,17728
|
|
3
|
+
fbuild/cli_utils.py,sha256=yi2UJidfsBWmcBwv6IS_FcXA5810jnmDN23lVJi7OvY,9929
|
|
4
|
+
fbuild/interrupt_utils.py,sha256=JuEAgImyF17ZP03ijCTRCXcxcTPt6eLZUmzqueyOEOQ,1026
|
|
5
|
+
fbuild/assets/example.txt,sha256=lTBovRjiz0_TgtAtbA1C5hNi2ffbqnNPqkKg6UiKCT8,54
|
|
6
|
+
fbuild/build/__init__.py,sha256=NS6A-b-yPCVcjbE0Elkx3_Qf-_O6sdk_aXumSheYjOA,2871
|
|
7
|
+
fbuild/build/archive_creator.py,sha256=L5ZMLK44jZFhROOsyQdk-8nBKbDqDDRAxlM9gbplK7Y,6919
|
|
8
|
+
fbuild/build/binary_generator.py,sha256=wDGtcPuQlKfMuxjJZdZqRdqQCbg9cAao4zaXKi3qArg,16042
|
|
9
|
+
fbuild/build/build_component_factory.py,sha256=bUfGNOVrO823TdGpEjNPpPrsM3ZXvvgwGVODLUbCZ28,4237
|
|
10
|
+
fbuild/build/build_state.py,sha256=MtnCof6nOtKyAqW8OFWuMK7GXOIwmG1TeBJtXiRq18Y,11168
|
|
11
|
+
fbuild/build/build_utils.py,sha256=RJH76Lcintpl_7QkPG70cl6JPFJ-mOWnyskj73YC0Fc,2958
|
|
12
|
+
fbuild/build/compilation_executor.py,sha256=pzLeavweXkvaliLQEpwxjYvw1WMZcRzxdOJIX0kfezs,15748
|
|
13
|
+
fbuild/build/compiler.py,sha256=YMUUonS6eGbOPgf0Vo9BaG7ms3Kts2PalgCUhoIjCbY,4181
|
|
14
|
+
fbuild/build/compiler_avr.py,sha256=9KG2IfWEK9VGHbsWe2Y36rcFAkq1dMXo5PX5TPKI3D4,17604
|
|
15
|
+
fbuild/build/configurable_compiler.py,sha256=qeGEft8a3mVs5Cl5gmwhBfh8hQPfIu9qQnfWvbG2udA,21531
|
|
16
|
+
fbuild/build/configurable_linker.py,sha256=tK6jHEojVOz7zqiBOa-jQZCC730LgjeRZrGtLiWxwxM,24141
|
|
17
|
+
fbuild/build/flag_builder.py,sha256=-_oqrYem--DW2EL0UhRzhrxpKr4r3hiamvwFEqLra-0,6070
|
|
18
|
+
fbuild/build/library_dependency_processor.py,sha256=EoyOZJX4lVYCasXL6S5g3q86jlMlR9zyf-xfCu5vUyE,5860
|
|
19
|
+
fbuild/build/linker.py,sha256=4ooKcSqQDn96KLxHAiWNbR0vuhDnDOXFFEKqp5x9UJE,23831
|
|
20
|
+
fbuild/build/orchestrator.py,sha256=KvKfyJw-SZR_X7c-iE-hLj4KvFkO-VXkwDG0VeNyoms,1792
|
|
21
|
+
fbuild/build/orchestrator_avr.py,sha256=IQrzzrFn0aUnJ2xQmUi5dJdhq0HEMrviZIHdZvlII6s,24006
|
|
22
|
+
fbuild/build/orchestrator_esp32.py,sha256=AbL6jwkUEYCMB84tZGgSEzRUkyOKkGm8aGERmbXrKGk,27580
|
|
23
|
+
fbuild/build/orchestrator_teensy.py,sha256=q3G50svOvAufJHFaqboCnVd9qMN-O3V6v1H42ReTMzQ,18451
|
|
24
|
+
fbuild/build/source_compilation_orchestrator.py,sha256=MPg21vjcHa2NVvTNta08ZsXDIhEKfeoKrRCo4SUBiVw,7009
|
|
25
|
+
fbuild/build/source_scanner.py,sha256=sypaXJ7epC6APRosKG8xtTXGV-ngK2_3PdLCg-pnS4c,17422
|
|
26
|
+
fbuild/config/__init__.py,sha256=3QSJUBVhJabUl2g8dglAp58U8nH5fh2gHZWIoIxIl8g,403
|
|
27
|
+
fbuild/config/board_config.py,sha256=rDSTmUDKlxpPUMbxuN5oPuYK5o9XFNibh_48Mobkkx4,14090
|
|
28
|
+
fbuild/config/board_loader.py,sha256=X64LJSISfP2pDx9FrNG5tkXqQ2wDfnp5WxHmpkfLXIk,3528
|
|
29
|
+
fbuild/config/ini_parser.py,sha256=Ab783_LzZkGA3HFYM5vb0DEvdW2dvfDIYUUhuc_6qmo,6608
|
|
30
|
+
fbuild/config/mcu_specs.py,sha256=GZYl_86ykdYvuj5oLUoD5zN7hOUnhh7dK4X3q5AFk-E,2145
|
|
31
|
+
fbuild/daemon/__init__.py,sha256=pEwvWKbyueRxb51q4PskH7Li0Qg_CqYA4krYvPkJOlQ,722
|
|
32
|
+
fbuild/daemon/client.py,sha256=vB5i51vujSPYzXaowDy95ehQqC7z-TRMpukilB2InuE,30014
|
|
33
|
+
fbuild/daemon/compilation_queue.py,sha256=l7LUBy81l_OhxocA0TDJVPT4FyU0dkbLwEEvFRGIaIo,10405
|
|
34
|
+
fbuild/daemon/daemon.py,sha256=KDKXuwRtQVGbjBpmJeWM-qDh2kUV2ujSXBharoOPc4c,17290
|
|
35
|
+
fbuild/daemon/daemon_context.py,sha256=yFfGKc4o2SSiTbeYp-BWiRjSx-UBsc5NpqPetDZ5tdI,7131
|
|
36
|
+
fbuild/daemon/error_collector.py,sha256=pKO1PYw7zsMJgZLS_lXOY4mYTfywR92tlzTpwngLIG4,9223
|
|
37
|
+
fbuild/daemon/file_cache.py,sha256=PSzrgf8aR5OHtv74Yif2oxiSdJGoktW4Rv7256ZEQ2Q,11116
|
|
38
|
+
fbuild/daemon/lock_manager.py,sha256=YekUO-7YhwG_A8r2Q87FpvTWoGL-1x1js_XUEjAfzXs,10727
|
|
39
|
+
fbuild/daemon/logging_utils.py,sha256=0lshNSYoqFxgm8vJdfF3bv_YGw3xvQ7uKHxy3jq0lZ4,5233
|
|
40
|
+
fbuild/daemon/messages.py,sha256=zrGGNp8kQhPRdAhc9nm0zvqNiLUJcAKgERm55jcySJQ,11093
|
|
41
|
+
fbuild/daemon/operation_registry.py,sha256=pg_HCrG4vriebeFNB4Nq5WP_3hdO7-nweVMLQJu-dlw,11617
|
|
42
|
+
fbuild/daemon/process_tracker.py,sha256=cm0sngT6AP7spNCEmE2NJmcZcnYcYEhBds6yLsE8Ze0,12536
|
|
43
|
+
fbuild/daemon/request_processor.py,sha256=7FV_9SMeJS2l0PXJP3lb6SZdcVNl8PLt82wIlEGuYKQ,14916
|
|
44
|
+
fbuild/daemon/status_manager.py,sha256=OMlvMjTFOBuvSImYlu6e_s3ceYKqJ5o1lLiApr6yMCk,7883
|
|
45
|
+
fbuild/daemon/subprocess_manager.py,sha256=9LMQgK5ndSC-iCuuvmYmDpH6uE8LvKMPKGCHm4-2JVI,12557
|
|
46
|
+
fbuild/daemon/processors/__init__.py,sha256=716AnzwanhBrzGiTRlhAidZaIFpal7fVo3PDcBpxIU8,518
|
|
47
|
+
fbuild/daemon/processors/build_processor.py,sha256=PsdS-94auA35-6iRhxyV64-MQKBtpsUJjStGmmJ1QdE,6301
|
|
48
|
+
fbuild/daemon/processors/deploy_processor.py,sha256=nl5ntc1D-3Uu7Cfj-YnTBWlyMIHJD6yk-5Xz_3tNhLk,12728
|
|
49
|
+
fbuild/daemon/processors/monitor_processor.py,sha256=ywg96mUmfDHvr5tdSnR6cxtclXjaBMbKViHeHpZP8I4,5547
|
|
50
|
+
fbuild/deploy/__init__.py,sha256=sXJx5ebFGaBx0b9wdafqQjvFcsW9aI7zaWsR6zkl2oY,401
|
|
51
|
+
fbuild/deploy/deployer.py,sha256=WiC4hrtt-NzUAXzXd1CaSieqBOHX7nqCZrwtjp1NeDc,1578
|
|
52
|
+
fbuild/deploy/deployer_esp32.py,sha256=lnZQrEDn2y8QToLReqyGclAKcp0rrTNyVp62W2mgAqs,11327
|
|
53
|
+
fbuild/deploy/monitor.py,sha256=ZyWXG_mszohzBB0yADe_H-pTti6zDjihY3dOBeXBzfc,19233
|
|
54
|
+
fbuild/packages/__init__.py,sha256=JbdXK0Ssk5K91XA_ERFLEVdepmXzYRlCtnESaRTEjhg,1724
|
|
55
|
+
fbuild/packages/archive_utils.py,sha256=jjrfx6IZllIQ6mCshO_QA7oiLkVYtlHHn-S35rS4aBU,51925
|
|
56
|
+
fbuild/packages/arduino_core.py,sha256=Ym_EFfb__Tp4HAexzbkdCuqqhd9Uvw7pa3eWelbIyCg,13235
|
|
57
|
+
fbuild/packages/cache.py,sha256=S_NvKI2hZAN1qN5YJ1gwG_f8YUWJwGf1yRoxxuusyaM,8238
|
|
58
|
+
fbuild/packages/downloader.py,sha256=YEIW2TDj9zvOfBH3b22lrKjPq6umdU90x7VOBAXcW0w,12048
|
|
59
|
+
fbuild/packages/framework_esp32.py,sha256=2uS94oWbE2_vssTebMKz_9g-ZOHCFsYgo5PvfR4IpgQ,19612
|
|
60
|
+
fbuild/packages/framework_teensy.py,sha256=3jbcaN91t5vE4A1Pd9nTdx89dwcg2NahCkiwrY3EMwA,11352
|
|
61
|
+
fbuild/packages/github_utils.py,sha256=iLwLpWaXPhaadJwScE_sWcmlzA5r-e5TuZY7-Yet4nY,2857
|
|
62
|
+
fbuild/packages/header_trampoline_cache.py,sha256=fupEB5mE6_dytWswx3-LqogVnw7wq_YRWCfHsy-14XY,14305
|
|
63
|
+
fbuild/packages/library_compiler.py,sha256=Giavoet3ijrNyshZQGw0mHFr11JSiPDn8aQ3dd_jng4,7244
|
|
64
|
+
fbuild/packages/library_manager.py,sha256=7QIYu8WYUf4g-GGzwnubjcqKiS92GOjkL_X9Jvx4Mtw,17704
|
|
65
|
+
fbuild/packages/library_manager_esp32.py,sha256=2GB1Mr4u0vUgcP4txT_L7XotWwDaYiHz9G-4VWQZrLc,13775
|
|
66
|
+
fbuild/packages/package.py,sha256=scgvVHnaHm0gBV55DPbn0a8AcHLiBLKgBGFU--R6a6M,3894
|
|
67
|
+
fbuild/packages/platform_esp32.py,sha256=F1rbxnYwaxftHoSrarxj0p73XTrdL2IninsDWshS3zE,13820
|
|
68
|
+
fbuild/packages/platform_teensy.py,sha256=wUTT1Zr4Hg-FI1JtbKkxUkPKSQHhG4k7YtrdvLsNrZU,9730
|
|
69
|
+
fbuild/packages/platform_utils.py,sha256=nE2nXDI6LDFTDqdndV2e9lY103m72H5nT7nKerQM3JM,3978
|
|
70
|
+
fbuild/packages/platformio_registry.py,sha256=OGfI88SysnnJhif2ntSmNgtoCId-quR8iZR1JPWuVJ4,10389
|
|
71
|
+
fbuild/packages/sdk_utils.py,sha256=XbPFT2dOJ8z4rU6gIVjt0wwkPEvaSPFu__R9UTV0-fc,9042
|
|
72
|
+
fbuild/packages/toolchain.py,sha256=HxC8HbufztiA-glrEqbc029AZer3WE2jerBIgVX0ZfE,14274
|
|
73
|
+
fbuild/packages/toolchain_binaries.py,sha256=qJXgrSTN9CxGwFSGdtjs_2-BnxjP68OltAPmRTO-69Y,6917
|
|
74
|
+
fbuild/packages/toolchain_esp32.py,sha256=QQAfQCKSaAzQMeWdSBWE3_4HX3MGwT4bJNxdo2dLoiM,16734
|
|
75
|
+
fbuild/packages/toolchain_metadata.py,sha256=ws8bt5O_Ay8PwZDiN15BTaoKh2U77IlmhRyvA706h3s,6367
|
|
76
|
+
fbuild/packages/toolchain_teensy.py,sha256=5bM49z4nbgAplZxmk8nVcOB-p7yGMLOWgzAnkChrKus,13584
|
|
77
|
+
fbuild/platform_configs/esp32.json,sha256=bynMS4DnDfG9Ka_wZQO1io-QygtJwMohmEaK_jlrDBA,4532
|
|
78
|
+
fbuild/platform_configs/esp32c2.json,sha256=phr00CLtw7bCD0cW7iHTX2ShtfVVrWibBx7cAvcF3BY,4438
|
|
79
|
+
fbuild/platform_configs/esp32c3.json,sha256=GgLERfXXbvZGnauiCnaYhgugKv1B7DADWiI3i0z0WZk,4427
|
|
80
|
+
fbuild/platform_configs/esp32c5.json,sha256=07wPF69U8MfOLup8H5CcguyCBq0kwBeU81Ka9BDFSRw,4691
|
|
81
|
+
fbuild/platform_configs/esp32c6.json,sha256=zRYpaOJ414ja5wrFiNgUb8kvZxyQBtvmJRkg9mmOrAc,4691
|
|
82
|
+
fbuild/platform_configs/esp32p4.json,sha256=OniO6KxL8iK_7qS3jW18Y8iJSt693a06vNyDEfcYSk0,4602
|
|
83
|
+
fbuild/platform_configs/esp32s3.json,sha256=iKtW28vzYPbDXGhcb78gm9tqYQTBvxPFI5kTRMaUmd8,4611
|
|
84
|
+
fbuild/platform_configs/imxrt1062.json,sha256=_eW8sDCnx4T8Y5uEtQruKquIvo01U6WcrEzPpH8b-94,1047
|
|
85
|
+
fbuild-1.1.0.dist-info/licenses/LICENSE,sha256=b6pOoifSXiUaz_lDS84vWlG3fr4yUKwB8fzkrH9R8bQ,1064
|
|
86
|
+
fbuild_lint/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
87
|
+
fbuild_lint/ruff_plugins/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
88
|
+
fbuild_lint/ruff_plugins/keyboard_interrupt_checker.py,sha256=zFxPRGx6M9tNEOl8o7eKEEPrU1ZytbqmwNiVyrhWgRk,6555
|
|
89
|
+
fbuild-1.1.0.dist-info/METADATA,sha256=G4jKhomRlSpafY3R09Y6tlZC0cM5WQ2BcO-xAcNIdF0,13203
|
|
90
|
+
fbuild-1.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
91
|
+
fbuild-1.1.0.dist-info/entry_points.txt,sha256=FoKJ3GeqwGCKFr7Zanl1f67qRYS_EQpA5s2GadeYwQU,146
|
|
92
|
+
fbuild-1.1.0.dist-info/top_level.txt,sha256=SP5cQb_9JGxIZk2wo2pH6RlSxePBRTEBPVvPti2ckhQ,19
|
|
93
|
+
fbuild-1.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2019 zackees
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
fbuild_lint/__init__.py
ADDED
|
File without changes
|
|
File without changes
|
|
@@ -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
|