summaryrefslogtreecommitdiff
path: root/lib/python
diff options
context:
space:
mode:
authorNick Brassel <nick@tzarc.org>2024-06-15 19:37:47 +1000
committerGitHub <noreply@github.com>2024-06-15 10:37:47 +0100
commit0262161914133e6abfc306e675dbac3ba816a6ee (patch)
tree042db91495759ceb4bc54895017a4420427d581d /lib/python
parentd4654ab8934f795bbfc294f5b128a94aaa645a78 (diff)
[CLI] Don't `exit()` when certain exceptions occur. (#23442)
Diffstat (limited to 'lib/python')
-rw-r--r--lib/python/qmk/cli/find.py3
-rw-r--r--lib/python/qmk/cli/generate/autocorrect_data.py12
-rwxr-xr-xlib/python/qmk/cli/mass_compile.py3
-rw-r--r--lib/python/qmk/cli/userspace/compile.py3
-rw-r--r--lib/python/qmk/cli/userspace/list.py3
-rwxr-xr-xlib/python/qmk/cli/via2json.py10
-rw-r--r--lib/python/qmk/commands.py3
-rw-r--r--lib/python/qmk/info.py3
-rw-r--r--lib/python/qmk/json_schema.py6
-rw-r--r--lib/python/qmk/util.py21
10 files changed, 55 insertions, 12 deletions
diff --git a/lib/python/qmk/cli/find.py b/lib/python/qmk/cli/find.py
index 8f3a29c90c..bfed91e22c 100644
--- a/lib/python/qmk/cli/find.py
+++ b/lib/python/qmk/cli/find.py
@@ -2,6 +2,7 @@
2""" 2"""
3from milc import cli 3from milc import cli
4from qmk.search import filter_help, search_keymap_targets 4from qmk.search import filter_help, search_keymap_targets
5from qmk.util import maybe_exit_config
5 6
6 7
7@cli.argument( 8@cli.argument(
@@ -19,6 +20,8 @@ from qmk.search import filter_help, search_keymap_targets
19def find(cli): 20def find(cli):
20 """Search through all keyboards and keymaps for a given search criteria. 21 """Search through all keyboards and keymaps for a given search criteria.
21 """ 22 """
23 maybe_exit_config(should_exit=False, should_reraise=True)
24
22 targets = search_keymap_targets([('all', cli.config.find.keymap)], cli.args.filter) 25 targets = search_keymap_targets([('all', cli.config.find.keymap)], cli.args.filter)
23 for target in sorted(targets, key=lambda t: (t.keyboard, t.keymap)): 26 for target in sorted(targets, key=lambda t: (t.keyboard, t.keymap)):
24 print(f'{target}') 27 print(f'{target}')
diff --git a/lib/python/qmk/cli/generate/autocorrect_data.py b/lib/python/qmk/cli/generate/autocorrect_data.py
index b11c66d95d..01a29b46fe 100644
--- a/lib/python/qmk/cli/generate/autocorrect_data.py
+++ b/lib/python/qmk/cli/generate/autocorrect_data.py
@@ -27,7 +27,6 @@ Example:
27For full documentation, see QMK Docs 27For full documentation, see QMK Docs
28""" 28"""
29 29
30import sys
31import textwrap 30import textwrap
32from typing import Any, Dict, Iterator, List, Tuple 31from typing import Any, Dict, Iterator, List, Tuple
33 32
@@ -38,6 +37,7 @@ from qmk.constants import GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE
38from qmk.keyboard import keyboard_completer, keyboard_folder 37from qmk.keyboard import keyboard_completer, keyboard_folder
39from qmk.keymap import keymap_completer, locate_keymap 38from qmk.keymap import keymap_completer, locate_keymap
40from qmk.path import normpath 39from qmk.path import normpath
40from qmk.util import maybe_exit
41 41
42KC_A = 4 42KC_A = 4
43KC_SPC = 0x2c 43KC_SPC = 0x2c
@@ -88,16 +88,16 @@ def parse_file(file_name: str) -> List[Tuple[str, str]]:
88 # Check that `typo` is valid. 88 # Check that `typo` is valid.
89 if not (all([c in TYPO_CHARS for c in typo])): 89 if not (all([c in TYPO_CHARS for c in typo])):
90 cli.log.error('{fg_red}Error:%d:{fg_reset} Typo "{fg_cyan}%s{fg_reset}" has characters other than a-z, \' and :.', line_number, typo) 90 cli.log.error('{fg_red}Error:%d:{fg_reset} Typo "{fg_cyan}%s{fg_reset}" has characters other than a-z, \' and :.', line_number, typo)
91 sys.exit(1) 91 maybe_exit(1)
92 for other_typo in typos: 92 for other_typo in typos:
93 if typo in other_typo or other_typo in typo: 93 if typo in other_typo or other_typo in typo:
94 cli.log.error('{fg_red}Error:%d:{fg_reset} Typos may not be substrings of one another, otherwise the longer typo would never trigger: "{fg_cyan}%s{fg_reset}" vs. "{fg_cyan}%s{fg_reset}".', line_number, typo, other_typo) 94 cli.log.error('{fg_red}Error:%d:{fg_reset} Typos may not be substrings of one another, otherwise the longer typo would never trigger: "{fg_cyan}%s{fg_reset}" vs. "{fg_cyan}%s{fg_reset}".', line_number, typo, other_typo)
95 sys.exit(1) 95 maybe_exit(1)
96 if len(typo) < 5: 96 if len(typo) < 5:
97 cli.log.warning('{fg_yellow}Warning:%d:{fg_reset} It is suggested that typos are at least 5 characters long to avoid false triggers: "{fg_cyan}%s{fg_reset}"', line_number, typo) 97 cli.log.warning('{fg_yellow}Warning:%d:{fg_reset} It is suggested that typos are at least 5 characters long to avoid false triggers: "{fg_cyan}%s{fg_reset}"', line_number, typo)
98 if len(typo) > 127: 98 if len(typo) > 127:
99 cli.log.error('{fg_red}Error:%d:{fg_reset} Typo exceeds 127 chars: "{fg_cyan}%s{fg_reset}"', line_number, typo) 99 cli.log.error('{fg_red}Error:%d:{fg_reset} Typo exceeds 127 chars: "{fg_cyan}%s{fg_reset}"', line_number, typo)
100 sys.exit(1) 100 maybe_exit(1)
101 101
102 check_typo_against_dictionary(typo, line_number, correct_words) 102 check_typo_against_dictionary(typo, line_number, correct_words)
103 103
@@ -136,7 +136,7 @@ def parse_file_lines(file_name: str) -> Iterator[Tuple[int, str, str]]:
136 tokens = [token.strip() for token in line.split('->', 1)] 136 tokens = [token.strip() for token in line.split('->', 1)]
137 if len(tokens) != 2 or not tokens[0]: 137 if len(tokens) != 2 or not tokens[0]:
138 print(f'Error:{line_number}: Invalid syntax: "{line}"') 138 print(f'Error:{line_number}: Invalid syntax: "{line}"')
139 sys.exit(1) 139 maybe_exit(1)
140 140
141 typo, correction = tokens 141 typo, correction = tokens
142 typo = typo.lower() # Force typos to lowercase. 142 typo = typo.lower() # Force typos to lowercase.
@@ -237,7 +237,7 @@ def encode_link(link: Dict[str, Any]) -> List[int]:
237 byte_offset = link['byte_offset'] 237 byte_offset = link['byte_offset']
238 if not (0 <= byte_offset <= 0xffff): 238 if not (0 <= byte_offset <= 0xffff):
239 cli.log.error('{fg_red}Error:{fg_reset} The autocorrection table is too large, a node link exceeds 64KB limit. Try reducing the autocorrection dict to fewer entries.') 239 cli.log.error('{fg_red}Error:{fg_reset} The autocorrection table is too large, a node link exceeds 64KB limit. Try reducing the autocorrection dict to fewer entries.')
240 sys.exit(1) 240 maybe_exit(1)
241 return [byte_offset & 255, byte_offset >> 8] 241 return [byte_offset & 255, byte_offset >> 8]
242 242
243 243
diff --git a/lib/python/qmk/cli/mass_compile.py b/lib/python/qmk/cli/mass_compile.py
index 7db704d6c2..d13afc6143 100755
--- a/lib/python/qmk/cli/mass_compile.py
+++ b/lib/python/qmk/cli/mass_compile.py
@@ -12,6 +12,7 @@ from qmk.constants import QMK_FIRMWARE
12from qmk.commands import find_make, get_make_parallel_args, build_environment 12from qmk.commands import find_make, get_make_parallel_args, build_environment
13from qmk.search import search_keymap_targets, search_make_targets 13from qmk.search import search_keymap_targets, search_make_targets
14from qmk.build_targets import BuildTarget, JsonKeymapBuildTarget 14from qmk.build_targets import BuildTarget, JsonKeymapBuildTarget
15from qmk.util import maybe_exit_config
15 16
16 17
17def mass_compile_targets(targets: List[BuildTarget], clean: bool, dry_run: bool, no_temp: bool, parallel: int, **env): 18def mass_compile_targets(targets: List[BuildTarget], clean: bool, dry_run: bool, no_temp: bool, parallel: int, **env):
@@ -100,6 +101,8 @@ all: {keyboard_safe}_{keymap_name}_binary
100def mass_compile(cli): 101def mass_compile(cli):
101 """Compile QMK Firmware against all keyboards. 102 """Compile QMK Firmware against all keyboards.
102 """ 103 """
104 maybe_exit_config(should_exit=False, should_reraise=True)
105
103 if len(cli.args.builds) > 0: 106 if len(cli.args.builds) > 0:
104 json_like_targets = list([Path(p) for p in filter(lambda e: Path(e).exists() and Path(e).suffix == '.json', cli.args.builds)]) 107 json_like_targets = list([Path(p) for p in filter(lambda e: Path(e).exists() and Path(e).suffix == '.json', cli.args.builds)])
105 make_like_targets = list(filter(lambda e: Path(e) not in json_like_targets, cli.args.builds)) 108 make_like_targets = list(filter(lambda e: Path(e) not in json_like_targets, cli.args.builds))
diff --git a/lib/python/qmk/cli/userspace/compile.py b/lib/python/qmk/cli/userspace/compile.py
index fb320a16f0..e8cdf6cd97 100644
--- a/lib/python/qmk/cli/userspace/compile.py
+++ b/lib/python/qmk/cli/userspace/compile.py
@@ -9,6 +9,7 @@ from qmk.userspace import UserspaceDefs
9from qmk.build_targets import JsonKeymapBuildTarget 9from qmk.build_targets import JsonKeymapBuildTarget
10from qmk.search import search_keymap_targets 10from qmk.search import search_keymap_targets
11from qmk.cli.mass_compile import mass_compile_targets 11from qmk.cli.mass_compile import mass_compile_targets
12from qmk.util import maybe_exit_config
12 13
13 14
14@cli.argument('-t', '--no-temp', arg_only=True, action='store_true', help="Remove temporary files during build.") 15@cli.argument('-t', '--no-temp', arg_only=True, action='store_true', help="Remove temporary files during build.")
@@ -22,6 +23,8 @@ def userspace_compile(cli):
22 cli.log.error('Could not determine QMK userspace location. Please run `qmk doctor` or `qmk userspace-doctor` to diagnose.') 23 cli.log.error('Could not determine QMK userspace location. Please run `qmk doctor` or `qmk userspace-doctor` to diagnose.')
23 return False 24 return False
24 25
26 maybe_exit_config(should_exit=False, should_reraise=True)
27
25 userspace = UserspaceDefs(QMK_USERSPACE / 'qmk.json') 28 userspace = UserspaceDefs(QMK_USERSPACE / 'qmk.json')
26 29
27 build_targets = [] 30 build_targets = []
diff --git a/lib/python/qmk/cli/userspace/list.py b/lib/python/qmk/cli/userspace/list.py
index a63f669dd7..8689c80a76 100644
--- a/lib/python/qmk/cli/userspace/list.py
+++ b/lib/python/qmk/cli/userspace/list.py
@@ -10,6 +10,7 @@ from qmk.build_targets import BuildTarget
10from qmk.keyboard import is_all_keyboards, keyboard_folder 10from qmk.keyboard import is_all_keyboards, keyboard_folder
11from qmk.keymap import is_keymap_target 11from qmk.keymap import is_keymap_target
12from qmk.search import search_keymap_targets 12from qmk.search import search_keymap_targets
13from qmk.util import maybe_exit_config
13 14
14 15
15@cli.argument('-e', '--expand', arg_only=True, action='store_true', help="Expands any use of `all` for either keyboard or keymap.") 16@cli.argument('-e', '--expand', arg_only=True, action='store_true', help="Expands any use of `all` for either keyboard or keymap.")
@@ -19,6 +20,8 @@ def userspace_list(cli):
19 cli.log.error('Could not determine QMK userspace location. Please run `qmk doctor` or `qmk userspace-doctor` to diagnose.') 20 cli.log.error('Could not determine QMK userspace location. Please run `qmk doctor` or `qmk userspace-doctor` to diagnose.')
20 return False 21 return False
21 22
23 maybe_exit_config(should_exit=False, should_reraise=True)
24
22 userspace = UserspaceDefs(QMK_USERSPACE / 'qmk.json') 25 userspace = UserspaceDefs(QMK_USERSPACE / 'qmk.json')
23 26
24 if cli.args.expand: 27 if cli.args.expand:
diff --git a/lib/python/qmk/cli/via2json.py b/lib/python/qmk/cli/via2json.py
index 77823b5d9d..73c9a61b3d 100755
--- a/lib/python/qmk/cli/via2json.py
+++ b/lib/python/qmk/cli/via2json.py
@@ -69,7 +69,7 @@ def _via_to_keymap(via_backup, keyboard_data, keymap_layout):
69 layout_data = keyboard_data['layouts'].get(keymap_layout) 69 layout_data = keyboard_data['layouts'].get(keymap_layout)
70 if not layout_data: 70 if not layout_data:
71 cli.log.error(f'LAYOUT macro {keymap_layout} is not a valid one for keyboard {cli.args.keyboard}!') 71 cli.log.error(f'LAYOUT macro {keymap_layout} is not a valid one for keyboard {cli.args.keyboard}!')
72 exit(1) 72 return None
73 73
74 layout_data = layout_data['layout'] 74 layout_data = layout_data['layout']
75 sorting_hat = list() 75 sorting_hat = list()
@@ -118,7 +118,7 @@ def via2json(cli):
118 keymap_layout = cli.args.layout if cli.args.layout else _find_via_layout_macro(cli.args.keyboard) 118 keymap_layout = cli.args.layout if cli.args.layout else _find_via_layout_macro(cli.args.keyboard)
119 if not keymap_layout: 119 if not keymap_layout:
120 cli.log.error(f"Couldn't find LAYOUT macro for keyboard {cli.args.keyboard}. Please specify it with the '-l' argument.") 120 cli.log.error(f"Couldn't find LAYOUT macro for keyboard {cli.args.keyboard}. Please specify it with the '-l' argument.")
121 exit(1) 121 return False
122 122
123 # Load the VIA backup json 123 # Load the VIA backup json
124 with cli.args.filename.open('r') as fd: 124 with cli.args.filename.open('r') as fd:
@@ -126,9 +126,15 @@ def via2json(cli):
126 126
127 # Generate keyboard metadata 127 # Generate keyboard metadata
128 keyboard_data = info_json(cli.args.keyboard) 128 keyboard_data = info_json(cli.args.keyboard)
129 if not keyboard_data:
130 cli.log.error(f'LAYOUT macro {keymap_layout} is not a valid one for keyboard {cli.args.keyboard}!')
131 return False
129 132
130 # Get keycode array 133 # Get keycode array
131 keymap_data = _via_to_keymap(via_backup, keyboard_data, keymap_layout) 134 keymap_data = _via_to_keymap(via_backup, keyboard_data, keymap_layout)
135 if not keymap_data:
136 cli.log.error(f'Could not extract valid keycode data from VIA backup matching keyboard {cli.args.keyboard}!')
137 return False
132 138
133 # Convert macros 139 # Convert macros
134 macro_data = list() 140 macro_data = list()
diff --git a/lib/python/qmk/commands.py b/lib/python/qmk/commands.py
index d95ff5f923..3db8353bfd 100644
--- a/lib/python/qmk/commands.py
+++ b/lib/python/qmk/commands.py
@@ -11,6 +11,7 @@ import jsonschema
11from qmk.constants import QMK_USERSPACE, HAS_QMK_USERSPACE 11from qmk.constants import QMK_USERSPACE, HAS_QMK_USERSPACE
12from qmk.json_schema import json_load, validate 12from qmk.json_schema import json_load, validate
13from qmk.keyboard import keyboard_alias_definitions 13from qmk.keyboard import keyboard_alias_definitions
14from qmk.util import maybe_exit
14 15
15 16
16def find_make(): 17def find_make():
@@ -52,7 +53,7 @@ def parse_configurator_json(configurator_file):
52 53
53 except jsonschema.ValidationError as e: 54 except jsonschema.ValidationError as e:
54 cli.log.error(f'Invalid JSON keymap: {configurator_file} : {e.message}') 55 cli.log.error(f'Invalid JSON keymap: {configurator_file} : {e.message}')
55 exit(1) 56 maybe_exit(1)
56 57
57 keyboard = user_keymap['keyboard'] 58 keyboard = user_keymap['keyboard']
58 aliases = keyboard_alias_definitions() 59 aliases = keyboard_alias_definitions()
diff --git a/lib/python/qmk/info.py b/lib/python/qmk/info.py
index ffc9d57d68..833271c09c 100644
--- a/lib/python/qmk/info.py
+++ b/lib/python/qmk/info.py
@@ -14,6 +14,7 @@ from qmk.keyboard import config_h, rules_mk
14from qmk.commands import parse_configurator_json 14from qmk.commands import parse_configurator_json
15from qmk.makefile import parse_rules_mk_file 15from qmk.makefile import parse_rules_mk_file
16from qmk.math import compute 16from qmk.math import compute
17from qmk.util import maybe_exit
17 18
18true_values = ['1', 'on', 'yes'] 19true_values = ['1', 'on', 'yes']
19false_values = ['0', 'off', 'no'] 20false_values = ['0', 'off', 'no']
@@ -208,7 +209,7 @@ def _validate(keyboard, info_data):
208 except jsonschema.ValidationError as e: 209 except jsonschema.ValidationError as e:
209 json_path = '.'.join([str(p) for p in e.absolute_path]) 210 json_path = '.'.join([str(p) for p in e.absolute_path])
210 cli.log.error('Invalid API data: %s: %s: %s', keyboard, json_path, e.message) 211 cli.log.error('Invalid API data: %s: %s: %s', keyboard, json_path, e.message)
211 exit(1) 212 maybe_exit(1)
212 213
213 214
214def info_json(keyboard): 215def info_json(keyboard):
diff --git a/lib/python/qmk/json_schema.py b/lib/python/qmk/json_schema.py
index 1d5f863807..b11a0ed7ea 100644
--- a/lib/python/qmk/json_schema.py
+++ b/lib/python/qmk/json_schema.py
@@ -11,6 +11,8 @@ from copy import deepcopy
11 11
12from milc import cli 12from milc import cli
13 13
14from qmk.util import maybe_exit
15
14 16
15def _dict_raise_on_duplicates(ordered_pairs): 17def _dict_raise_on_duplicates(ordered_pairs):
16 """Reject duplicate keys.""" 18 """Reject duplicate keys."""
@@ -38,10 +40,10 @@ def _json_load_impl(json_file, strict=True):
38 40
39 except (json.decoder.JSONDecodeError, hjson.HjsonDecodeError) as e: 41 except (json.decoder.JSONDecodeError, hjson.HjsonDecodeError) as e:
40 cli.log.error('Invalid JSON encountered attempting to load {fg_cyan}%s{fg_reset}:\n\t{fg_red}%s', json_file, e) 42 cli.log.error('Invalid JSON encountered attempting to load {fg_cyan}%s{fg_reset}:\n\t{fg_red}%s', json_file, e)
41 exit(1) 43 maybe_exit(1)
42 except Exception as e: 44 except Exception as e:
43 cli.log.error('Unknown error attempting to load {fg_cyan}%s{fg_reset}:\n\t{fg_red}%s', json_file, e) 45 cli.log.error('Unknown error attempting to load {fg_cyan}%s{fg_reset}:\n\t{fg_red}%s', json_file, e)
44 exit(1) 46 maybe_exit(1)
45 47
46 48
47def json_load(json_file, strict=True): 49def json_load(json_file, strict=True):
diff --git a/lib/python/qmk/util.py b/lib/python/qmk/util.py
index db7debd578..0145ab1354 100644
--- a/lib/python/qmk/util.py
+++ b/lib/python/qmk/util.py
@@ -2,9 +2,30 @@
2""" 2"""
3import contextlib 3import contextlib
4import multiprocessing 4import multiprocessing
5import sys
5 6
6from milc import cli 7from milc import cli
7 8
9maybe_exit_should_exit = True
10maybe_exit_reraise = False
11
12
13# Controls whether or not early `exit()` calls should be made
14def maybe_exit(rc):
15 if maybe_exit_should_exit:
16 sys.exit(rc)
17 if maybe_exit_reraise:
18 e = sys.exception()
19 if e:
20 raise e
21
22
23def maybe_exit_config(should_exit: bool = True, should_reraise: bool = False):
24 global maybe_exit_should_exit
25 global maybe_exit_reraise
26 maybe_exit_should_exit = should_exit
27 maybe_exit_reraise = should_reraise
28
8 29
9@contextlib.contextmanager 30@contextlib.contextmanager
10def parallelize(): 31def parallelize():