diff --git a/lib/python/qmk/cli/generate/api.py b/lib/python/qmk/cli/generate/api.py index 7f7c05f6e23..ad6db504b0b 100755 --- a/lib/python/qmk/cli/generate/api.py +++ b/lib/python/qmk/cli/generate/api.py @@ -23,15 +23,18 @@ def _list_constants(output_folder): """Produce a map of available constants """ ret = {} - for file in (output_folder / 'constants').glob('**/*_[0-9].[0-9].[0-9].json'): - name, version = file.stem.rsplit('_', 1) + for file in (output_folder / 'constants').glob('**/*.json'): + name, _, version = file.stem.rpartition('_') + parts = version.split('.') + if not name or len(parts) != 3 or not all(part.isascii() and part.isdigit() for part in parts): + continue if name not in ret: ret[name] = [] ret[name].append(version) # Ensure content is sorted for name in ret: - ret[name] = sorted(ret[name]) + ret[name] = sorted(ret[name], key=lambda version: tuple(map(int, version.split('.')))) return ret diff --git a/lib/python/qmk/keycodes.py b/lib/python/qmk/keycodes.py index 9e4664e5f10..b4e7a22abdd 100644 --- a/lib/python/qmk/keycodes.py +++ b/lib/python/qmk/keycodes.py @@ -9,10 +9,13 @@ EXTRAS_PATH = KEYCODES_PATH / 'extras' def _find_versions(path, prefix): ret = [] - for file in path.glob(f'{prefix}_[0-9].[0-9].[0-9].hjson'): - ret.append(file.stem.split('_')[-1]) + for file in path.glob(f'{prefix}_*.hjson'): + version = file.stem[len(prefix) + 1:] + parts = version.split('.') + if len(parts) == 3 and all(part.isascii() and part.isdigit() for part in parts): + ret.append(version) - ret.sort(reverse=True) + ret.sort(key=lambda version: tuple(map(int, version.split('.'))), reverse=True) return ret @@ -112,7 +115,10 @@ def list_languages(): """Return available languages """ ret = set() - for file in EXTRAS_PATH.glob('keycodes_*_[0-9].[0-9].[0-9].hjson'): - ret.add(file.stem.split('_')[1]) + for file in EXTRAS_PATH.glob('keycodes_*.hjson'): + name, _, version = file.stem.rpartition('_') + parts = version.split('.') + if len(parts) == 3 and all(part.isascii() and part.isdigit() for part in parts): + ret.add(name[len('keycodes_'):]) return ret diff --git a/lib/python/qmk/tests/test_qmk_keycodes.py b/lib/python/qmk/tests/test_qmk_keycodes.py new file mode 100644 index 00000000000..934f7e526a8 --- /dev/null +++ b/lib/python/qmk/tests/test_qmk_keycodes.py @@ -0,0 +1,36 @@ +from pathlib import Path +from tempfile import TemporaryDirectory +from unittest.mock import patch + +from qmk import keycodes + + +def test_list_versions_orders_multi_digit_versions_and_ignores_fragments(): + with TemporaryDirectory() as temporary: + path = Path(temporary) + for version in ('0.0.9', '0.0.10', '0.1.0'): + (path / f'keycodes_{version}.hjson').write_text('{}') + (path / 'keycodes_0.0.10_quantum.hjson').write_text('{}') + (path / 'keycodes_invalid.hjson').write_text('{}') + with patch.object(keycodes, 'KEYCODES_PATH', path): + assert keycodes.list_versions() == ['0.1.0', '0.0.10', '0.0.9'] + + +def test_list_language_versions_supports_multi_digit_patch_versions(): + with TemporaryDirectory() as temporary: + path = Path(temporary) + (path / 'keycodes_us_international_0.0.9.hjson').write_text('{}') + (path / 'keycodes_us_international_0.0.10.hjson').write_text('{}') + (path / 'keycodes_us_0.0.11.hjson').write_text('{}') + with patch.object(keycodes, 'EXTRAS_PATH', path): + assert keycodes.list_versions('us_international') == ['0.0.10', '0.0.9'] + + +def test_list_languages_keeps_full_names_and_multi_digit_versions(): + with TemporaryDirectory() as temporary: + path = Path(temporary) + (path / 'keycodes_us_international_0.0.10.hjson').write_text('{}') + (path / 'keycodes_french_0.0.9.hjson').write_text('{}') + (path / 'keycodes_french_0.0.10_quantum.hjson').write_text('{}') + with patch.object(keycodes, 'EXTRAS_PATH', path): + assert keycodes.list_languages() == {'us_international', 'french'}