diff options
author | Zach White <skullydazed@gmail.com> | 2020-10-25 14:48:44 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-10-25 14:48:44 -0700 |
commit | 0c42f91f4ccf98a37f055afb777ed491da56335e (patch) | |
tree | 547344d80fe7bf75ff3f348eefbc19dbdd346a8a | |
parent | 8ef82c466e73e555fd74107d4c57e678d7152ecc (diff) | |
download | qmk_firmware-0c42f91f4ccf98a37f055afb777ed491da56335e.tar.gz qmk_firmware-0c42f91f4ccf98a37f055afb777ed491da56335e.zip |
Generate api data on each push (#10609)
* add new qmk generate-api command, to generate a complete set of API data.
* Generate api data and push it to the keyboard repo
* fix typo
* Apply suggestions from code review
Co-authored-by: Joel Challis <git@zvecr.com>
* fixup api workflow
* remove file-changes-action
* use a more mainstream github action
* fix yaml error
* Apply suggestions from code review
Co-authored-by: Erovia <Erovia@users.noreply.github.com>
* more uniform date handling
* make flake8 happy
* Update lib/python/qmk/decorators.py
Co-authored-by: Erovia <Erovia@users.noreply.github.com>
Co-authored-by: Joel Challis <git@zvecr.com>
Co-authored-by: Erovia <Erovia@users.noreply.github.com>
-rw-r--r-- | .github/workflows/api.yml | 35 | ||||
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | api_data/_config.yml | 1 | ||||
-rw-r--r-- | api_data/readme.md | 5 | ||||
-rw-r--r-- | lib/python/qmk/cli/__init__.py | 1 | ||||
-rw-r--r-- | lib/python/qmk/cli/c2json.py | 2 | ||||
-rw-r--r-- | lib/python/qmk/cli/generate/__init__.py | 1 | ||||
-rwxr-xr-x | lib/python/qmk/cli/generate/api.py | 58 | ||||
-rwxr-xr-x | lib/python/qmk/cli/info.py | 56 | ||||
-rwxr-xr-x | lib/python/qmk/cli/json2c.py | 2 | ||||
-rw-r--r-- | lib/python/qmk/cli/list/keyboards.py | 19 | ||||
-rw-r--r-- | lib/python/qmk/constants.py | 5 | ||||
-rw-r--r-- | lib/python/qmk/datetime.py | 29 | ||||
-rw-r--r-- | lib/python/qmk/decorators.py | 36 | ||||
-rw-r--r-- | lib/python/qmk/info.py | 8 | ||||
-rw-r--r-- | lib/python/qmk/keyboard.py | 20 | ||||
-rw-r--r-- | lib/python/qmk/keymap.py | 219 | ||||
-rw-r--r-- | lib/python/qmk/tests/test_qmk_keymap.py | 24 |
18 files changed, 397 insertions, 125 deletions
diff --git a/.github/workflows/api.yml b/.github/workflows/api.yml new file mode 100644 index 000000000..7a7bf75d0 --- /dev/null +++ b/.github/workflows/api.yml | |||
@@ -0,0 +1,35 @@ | |||
1 | name: Update API Data | ||
2 | |||
3 | on: | ||
4 | push: | ||
5 | branches: | ||
6 | - master | ||
7 | paths: | ||
8 | - 'keyboards/**' | ||
9 | - 'layouts/community/**' | ||
10 | |||
11 | jobs: | ||
12 | api_data: | ||
13 | runs-on: ubuntu-latest | ||
14 | container: qmkfm/base_container | ||
15 | |||
16 | steps: | ||
17 | - uses: actions/checkout@v2 | ||
18 | with: | ||
19 | fetch-depth: 1 | ||
20 | persist-credentials: false | ||
21 | |||
22 | - name: Generate API Data | ||
23 | run: qmk generate-api | ||
24 | |||
25 | - name: Upload API Data | ||
26 | uses: JamesIves/github-pages-deploy-action@3.7.1 | ||
27 | with: | ||
28 | ACCESS_TOKEN: ${{ secrets.API_TOKEN_GITHUB }} | ||
29 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
30 | BRANCH: main | ||
31 | FOLDER: api_data/v1 | ||
32 | CLEAN: true | ||
33 | GIT_CONFIG_EMAIL: hello@qmk.fm | ||
34 | REPOSITORY_NAME: qmk/qmk_keyboards | ||
35 | TARGET_FOLDER: v1 | ||
diff --git a/.gitignore b/.gitignore index 91d283e69..d6846cf63 100644 --- a/.gitignore +++ b/.gitignore | |||
@@ -16,6 +16,7 @@ | |||
16 | *.swp | 16 | *.swp |
17 | tags | 17 | tags |
18 | *~ | 18 | *~ |
19 | api_data/v1 | ||
19 | build/ | 20 | build/ |
20 | .build/ | 21 | .build/ |
21 | *.bak | 22 | *.bak |
diff --git a/api_data/_config.yml b/api_data/_config.yml new file mode 100644 index 000000000..277f1f2c5 --- /dev/null +++ b/api_data/_config.yml | |||
@@ -0,0 +1 @@ | |||
theme: jekyll-theme-cayman | |||
diff --git a/api_data/readme.md b/api_data/readme.md new file mode 100644 index 000000000..a4b2c6bce --- /dev/null +++ b/api_data/readme.md | |||
@@ -0,0 +1,5 @@ | |||
1 | # QMK Keyboard Metadata | ||
2 | |||
3 | This directory contains machine parsable data about keyboards supported by QMK. The latest version is always available online at <https://keyboards.qmk.fm>. | ||
4 | |||
5 | Do not edit anything here by hand. It is generated with the `qmk generate-api` command. | ||
diff --git a/lib/python/qmk/cli/__init__.py b/lib/python/qmk/cli/__init__.py index ba964ebbb..47e1b4435 100644 --- a/lib/python/qmk/cli/__init__.py +++ b/lib/python/qmk/cli/__init__.py | |||
@@ -13,6 +13,7 @@ from . import config | |||
13 | from . import docs | 13 | from . import docs |
14 | from . import doctor | 14 | from . import doctor |
15 | from . import flash | 15 | from . import flash |
16 | from . import generate | ||
16 | from . import hello | 17 | from . import hello |
17 | from . import info | 18 | from . import info |
18 | from . import json | 19 | from . import json |
diff --git a/lib/python/qmk/cli/c2json.py b/lib/python/qmk/cli/c2json.py index 0267303fd..8c8bd1f57 100644 --- a/lib/python/qmk/cli/c2json.py +++ b/lib/python/qmk/cli/c2json.py | |||
@@ -44,7 +44,7 @@ def c2json(cli): | |||
44 | 44 | ||
45 | # Generate the keymap.json | 45 | # Generate the keymap.json |
46 | try: | 46 | try: |
47 | keymap_json = qmk.keymap.generate(keymap_json['keyboard'], keymap_json['layout'], keymap_json['layers'], type='json', keymap=keymap_json['keymap']) | 47 | keymap_json = qmk.keymap.generate_json(keymap_json['keymap'], keymap_json['keyboard'], keymap_json['layout'], keymap_json['layers']) |
48 | except KeyError: | 48 | except KeyError: |
49 | cli.log.error('Something went wrong. Try to use --no-cpp.') | 49 | cli.log.error('Something went wrong. Try to use --no-cpp.') |
50 | sys.exit(1) | 50 | sys.exit(1) |
diff --git a/lib/python/qmk/cli/generate/__init__.py b/lib/python/qmk/cli/generate/__init__.py new file mode 100644 index 000000000..4dc7607ef --- /dev/null +++ b/lib/python/qmk/cli/generate/__init__.py | |||
@@ -0,0 +1 @@ | |||
from . import api | |||
diff --git a/lib/python/qmk/cli/generate/api.py b/lib/python/qmk/cli/generate/api.py new file mode 100755 index 000000000..9807a9cd6 --- /dev/null +++ b/lib/python/qmk/cli/generate/api.py | |||
@@ -0,0 +1,58 @@ | |||
1 | """This script automates the generation of the QMK API data. | ||
2 | """ | ||
3 | from pathlib import Path | ||
4 | from shutil import copyfile | ||
5 | import json | ||
6 | |||
7 | from milc import cli | ||
8 | |||
9 | from qmk.datetime import current_datetime | ||
10 | from qmk.info import info_json | ||
11 | from qmk.keyboard import list_keyboards | ||
12 | |||
13 | |||
14 | @cli.subcommand('Creates a new keymap for the keyboard of your choosing', hidden=False if cli.config.user.developer else True) | ||
15 | def generate_api(cli): | ||
16 | """Generates the QMK API data. | ||
17 | """ | ||
18 | api_data_dir = Path('api_data') | ||
19 | v1_dir = api_data_dir / 'v1' | ||
20 | keyboard_list = v1_dir / 'keyboard_list.json' | ||
21 | keyboard_all = v1_dir / 'keyboards.json' | ||
22 | usb_file = v1_dir / 'usb.json' | ||
23 | |||
24 | if not api_data_dir.exists(): | ||
25 | api_data_dir.mkdir() | ||
26 | |||
27 | kb_all = {'last_updated': current_datetime(), 'keyboards': {}} | ||
28 | usb_list = {'last_updated': current_datetime(), 'devices': {}} | ||
29 | |||
30 | # Generate and write keyboard specific JSON files | ||
31 | for keyboard_name in list_keyboards(): | ||
32 | kb_all['keyboards'][keyboard_name] = info_json(keyboard_name) | ||
33 | keyboard_dir = v1_dir / 'keyboards' / keyboard_name | ||
34 | keyboard_info = keyboard_dir / 'info.json' | ||
35 | keyboard_readme = keyboard_dir / 'readme.md' | ||
36 | keyboard_readme_src = Path('keyboards') / keyboard_name / 'readme.md' | ||
37 | |||
38 | keyboard_dir.mkdir(parents=True, exist_ok=True) | ||
39 | keyboard_info.write_text(json.dumps(kb_all['keyboards'][keyboard_name])) | ||
40 | |||
41 | if keyboard_readme_src.exists(): | ||
42 | copyfile(keyboard_readme_src, keyboard_readme) | ||
43 | |||
44 | if 'usb' in kb_all['keyboards'][keyboard_name]: | ||
45 | usb = kb_all['keyboards'][keyboard_name]['usb'] | ||
46 | |||
47 | if usb['vid'] not in usb_list['devices']: | ||
48 | usb_list['devices'][usb['vid']] = {} | ||
49 | |||
50 | if usb['pid'] not in usb_list['devices'][usb['vid']]: | ||
51 | usb_list['devices'][usb['vid']][usb['pid']] = {} | ||
52 | |||
53 | usb_list['devices'][usb['vid']][usb['pid']][keyboard_name] = usb | ||
54 | |||
55 | # Write the global JSON files | ||
56 | keyboard_list.write_text(json.dumps({'last_updated': current_datetime(), 'keyboards': sorted(kb_all['keyboards'])})) | ||
57 | keyboard_all.write_text(json.dumps(kb_all)) | ||
58 | usb_file.write_text(json.dumps(usb_list)) | ||
diff --git a/lib/python/qmk/cli/info.py b/lib/python/qmk/cli/info.py index 0e64d4074..44ce1186a 100755 --- a/lib/python/qmk/cli/info.py +++ b/lib/python/qmk/cli/info.py | |||
@@ -16,7 +16,7 @@ ROW_LETTERS = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnop' | |||
16 | COL_LETTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijilmnopqrstuvwxyz' | 16 | COL_LETTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijilmnopqrstuvwxyz' |
17 | 17 | ||
18 | 18 | ||
19 | def show_keymap(info_json, title_caps=True): | 19 | def show_keymap(kb_info_json, title_caps=True): |
20 | """Render the keymap in ascii art. | 20 | """Render the keymap in ascii art. |
21 | """ | 21 | """ |
22 | keymap_path = locate_keymap(cli.config.info.keyboard, cli.config.info.keymap) | 22 | keymap_path = locate_keymap(cli.config.info.keyboard, cli.config.info.keymap) |
@@ -36,7 +36,7 @@ def show_keymap(info_json, title_caps=True): | |||
36 | else: | 36 | else: |
37 | cli.echo('{fg_cyan}layer_%s{fg_reset}:', layer_num) | 37 | cli.echo('{fg_cyan}layer_%s{fg_reset}:', layer_num) |
38 | 38 | ||
39 | print(render_layout(info_json['layouts'][layout_name]['layout'], layer)) | 39 | print(render_layout(kb_info_json['layouts'][layout_name]['layout'], layer)) |
40 | 40 | ||
41 | 41 | ||
42 | def show_layouts(kb_info_json, title_caps=True): | 42 | def show_layouts(kb_info_json, title_caps=True): |
@@ -48,10 +48,10 @@ def show_layouts(kb_info_json, title_caps=True): | |||
48 | print(layout_art) # Avoid passing dirty data to cli.echo() | 48 | print(layout_art) # Avoid passing dirty data to cli.echo() |
49 | 49 | ||
50 | 50 | ||
51 | def show_matrix(info_json, title_caps=True): | 51 | def show_matrix(kb_info_json, title_caps=True): |
52 | """Render the layout with matrix labels in ascii art. | 52 | """Render the layout with matrix labels in ascii art. |
53 | """ | 53 | """ |
54 | for layout_name, layout in info_json['layouts'].items(): | 54 | for layout_name, layout in kb_info_json['layouts'].items(): |
55 | # Build our label list | 55 | # Build our label list |
56 | labels = [] | 56 | labels = [] |
57 | for key in layout['layout']: | 57 | for key in layout['layout']: |
@@ -69,54 +69,54 @@ def show_matrix(info_json, title_caps=True): | |||
69 | else: | 69 | else: |
70 | cli.echo('{fg_blue}matrix_%s{fg_reset}:', layout_name) | 70 | cli.echo('{fg_blue}matrix_%s{fg_reset}:', layout_name) |
71 | 71 | ||
72 | print(render_layout(info_json['layouts'][layout_name]['layout'], labels)) | 72 | print(render_layout(kb_info_json['layouts'][layout_name]['layout'], labels)) |
73 | 73 | ||
74 | 74 | ||
75 | def print_friendly_output(info_json): | 75 | def print_friendly_output(kb_info_json): |
76 | """Print the info.json in a friendly text format. | 76 | """Print the info.json in a friendly text format. |
77 | """ | 77 | """ |
78 | cli.echo('{fg_blue}Keyboard Name{fg_reset}: %s', info_json.get('keyboard_name', 'Unknown')) | 78 | cli.echo('{fg_blue}Keyboard Name{fg_reset}: %s', kb_info_json.get('keyboard_name', 'Unknown')) |
79 | cli.echo('{fg_blue}Manufacturer{fg_reset}: %s', info_json.get('manufacturer', 'Unknown')) | 79 | cli.echo('{fg_blue}Manufacturer{fg_reset}: %s', kb_info_json.get('manufacturer', 'Unknown')) |
80 | if 'url' in info_json: | 80 | if 'url' in kb_info_json: |
81 | cli.echo('{fg_blue}Website{fg_reset}: %s', info_json.get('url', '')) | 81 | cli.echo('{fg_blue}Website{fg_reset}: %s', kb_info_json.get('url', '')) |
82 | if info_json.get('maintainer', 'qmk') == 'qmk': | 82 | if kb_info_json.get('maintainer', 'qmk') == 'qmk': |
83 | cli.echo('{fg_blue}Maintainer{fg_reset}: QMK Community') | 83 | cli.echo('{fg_blue}Maintainer{fg_reset}: QMK Community') |
84 | else: | 84 | else: |
85 | cli.echo('{fg_blue}Maintainer{fg_reset}: %s', info_json['maintainer']) | 85 | cli.echo('{fg_blue}Maintainer{fg_reset}: %s', kb_info_json['maintainer']) |
86 | cli.echo('{fg_blue}Keyboard Folder{fg_reset}: %s', info_json.get('keyboard_folder', 'Unknown')) | 86 | cli.echo('{fg_blue}Keyboard Folder{fg_reset}: %s', kb_info_json.get('keyboard_folder', 'Unknown')) |
87 | cli.echo('{fg_blue}Layouts{fg_reset}: %s', ', '.join(sorted(info_json['layouts'].keys()))) | 87 | cli.echo('{fg_blue}Layouts{fg_reset}: %s', ', '.join(sorted(kb_info_json['layouts'].keys()))) |
88 | if 'width' in info_json and 'height' in info_json: | 88 | if 'width' in kb_info_json and 'height' in kb_info_json: |
89 | cli.echo('{fg_blue}Size{fg_reset}: %s x %s' % (info_json['width'], info_json['height'])) | 89 | cli.echo('{fg_blue}Size{fg_reset}: %s x %s' % (kb_info_json['width'], kb_info_json['height'])) |
90 | cli.echo('{fg_blue}Processor{fg_reset}: %s', info_json.get('processor', 'Unknown')) | 90 | cli.echo('{fg_blue}Processor{fg_reset}: %s', kb_info_json.get('processor', 'Unknown')) |
91 | cli.echo('{fg_blue}Bootloader{fg_reset}: %s', info_json.get('bootloader', 'Unknown')) | 91 | cli.echo('{fg_blue}Bootloader{fg_reset}: %s', kb_info_json.get('bootloader', 'Unknown')) |
92 | 92 | ||
93 | if cli.config.info.layouts: | 93 | if cli.config.info.layouts: |
94 | show_layouts(info_json, True) | 94 | show_layouts(kb_info_json, True) |
95 | 95 | ||
96 | if cli.config.info.matrix: | 96 | if cli.config.info.matrix: |
97 | show_matrix(info_json, True) | 97 | show_matrix(kb_info_json, True) |
98 | 98 | ||
99 | if cli.config_source.info.keymap and cli.config_source.info.keymap != 'config_file': | 99 | if cli.config_source.info.keymap and cli.config_source.info.keymap != 'config_file': |
100 | show_keymap(info_json, True) | 100 | show_keymap(kb_info_json, True) |
101 | 101 | ||
102 | 102 | ||
103 | def print_text_output(info_json): | 103 | def print_text_output(kb_info_json): |
104 | """Print the info.json in a plain text format. | 104 | """Print the info.json in a plain text format. |
105 | """ | 105 | """ |
106 | for key in sorted(info_json): | 106 | for key in sorted(kb_info_json): |
107 | if key == 'layouts': | 107 | if key == 'layouts': |
108 | cli.echo('{fg_blue}layouts{fg_reset}: %s', ', '.join(sorted(info_json['layouts'].keys()))) | 108 | cli.echo('{fg_blue}layouts{fg_reset}: %s', ', '.join(sorted(kb_info_json['layouts'].keys()))) |
109 | else: | 109 | else: |
110 | cli.echo('{fg_blue}%s{fg_reset}: %s', key, info_json[key]) | 110 | cli.echo('{fg_blue}%s{fg_reset}: %s', key, kb_info_json[key]) |
111 | 111 | ||
112 | if cli.config.info.layouts: | 112 | if cli.config.info.layouts: |
113 | show_layouts(info_json, False) | 113 | show_layouts(kb_info_json, False) |
114 | 114 | ||
115 | if cli.config.info.matrix: | 115 | if cli.config.info.matrix: |
116 | show_matrix(info_json, False) | 116 | show_matrix(kb_info_json, False) |
117 | 117 | ||
118 | if cli.config_source.info.keymap and cli.config_source.info.keymap != 'config_file': | 118 | if cli.config_source.info.keymap and cli.config_source.info.keymap != 'config_file': |
119 | show_keymap(info_json, False) | 119 | show_keymap(kb_info_json, False) |
120 | 120 | ||
121 | 121 | ||
122 | @cli.argument('-kb', '--keyboard', help='Keyboard to show info for.') | 122 | @cli.argument('-kb', '--keyboard', help='Keyboard to show info for.') |
diff --git a/lib/python/qmk/cli/json2c.py b/lib/python/qmk/cli/json2c.py index 2a9009436..426078063 100755 --- a/lib/python/qmk/cli/json2c.py +++ b/lib/python/qmk/cli/json2c.py | |||
@@ -38,7 +38,7 @@ def json2c(cli): | |||
38 | user_keymap = json.load(fd) | 38 | user_keymap = json.load(fd) |
39 | 39 | ||
40 | # Generate the keymap | 40 | # Generate the keymap |
41 | keymap_c = qmk.keymap.generate(user_keymap['keyboard'], user_keymap['layout'], user_keymap['layers']) | 41 | keymap_c = qmk.keymap.generate_c(user_keymap['keyboard'], user_keymap['layout'], user_keymap['layers']) |
42 | 42 | ||
43 | if cli.args.output: | 43 | if cli.args.output: |
44 | cli.args.output.parent.mkdir(parents=True, exist_ok=True) | 44 | cli.args.output.parent.mkdir(parents=True, exist_ok=True) |
diff --git a/lib/python/qmk/cli/list/keyboards.py b/lib/python/qmk/cli/list/keyboards.py index ca0c5661a..8b6c45167 100644 --- a/lib/python/qmk/cli/list/keyboards.py +++ b/lib/python/qmk/cli/list/keyboards.py | |||
@@ -1,28 +1,13 @@ | |||
1 | """List the keyboards currently defined within QMK | 1 | """List the keyboards currently defined within QMK |
2 | """ | 2 | """ |
3 | # We avoid pathlib here because this is performance critical code. | ||
4 | import os | ||
5 | import glob | ||
6 | |||
7 | from milc import cli | 3 | from milc import cli |
8 | 4 | ||
9 | BASE_PATH = os.path.join(os.getcwd(), "keyboards") + os.path.sep | 5 | import qmk.keyboard |
10 | KB_WILDCARD = os.path.join(BASE_PATH, "**", "rules.mk") | ||
11 | |||
12 | |||
13 | def find_name(path): | ||
14 | """Determine the keyboard name by stripping off the base_path and rules.mk. | ||
15 | """ | ||
16 | return path.replace(BASE_PATH, "").replace(os.path.sep + "rules.mk", "") | ||
17 | 6 | ||
18 | 7 | ||
19 | @cli.subcommand("List the keyboards currently defined within QMK") | 8 | @cli.subcommand("List the keyboards currently defined within QMK") |
20 | def list_keyboards(cli): | 9 | def list_keyboards(cli): |
21 | """List the keyboards currently defined within QMK | 10 | """List the keyboards currently defined within QMK |
22 | """ | 11 | """ |
23 | # find everywhere we have rules.mk where keymaps isn't in the path | 12 | for keyboard_name in qmk.keyboard.list_keyboards(): |
24 | paths = [path for path in glob.iglob(KB_WILDCARD, recursive=True) if 'keymaps' not in path] | ||
25 | |||
26 | # Extract the keyboard name from the path and print it | ||
27 | for keyboard_name in sorted(map(find_name, paths)): | ||
28 | print(keyboard_name) | 13 | print(keyboard_name) |
diff --git a/lib/python/qmk/constants.py b/lib/python/qmk/constants.py index 102111d7c..94ab68e5e 100644 --- a/lib/python/qmk/constants.py +++ b/lib/python/qmk/constants.py | |||
@@ -12,3 +12,8 @@ MAX_KEYBOARD_SUBFOLDERS = 5 | |||
12 | CHIBIOS_PROCESSORS = 'cortex-m0', 'cortex-m0plus', 'cortex-m3', 'cortex-m4', 'MKL26Z64', 'MK20DX128', 'MK20DX256', 'STM32F042', 'STM32F072', 'STM32F103', 'STM32F303', 'STM32F401', 'STM32F411' | 12 | CHIBIOS_PROCESSORS = 'cortex-m0', 'cortex-m0plus', 'cortex-m3', 'cortex-m4', 'MKL26Z64', 'MK20DX128', 'MK20DX256', 'STM32F042', 'STM32F072', 'STM32F103', 'STM32F303', 'STM32F401', 'STM32F411' |
13 | LUFA_PROCESSORS = 'atmega16u2', 'atmega32u2', 'atmega16u4', 'atmega32u4', 'at90usb646', 'at90usb647', 'at90usb1286', 'at90usb1287', None | 13 | LUFA_PROCESSORS = 'atmega16u2', 'atmega32u2', 'atmega16u4', 'atmega32u4', 'at90usb646', 'at90usb647', 'at90usb1286', 'at90usb1287', None |
14 | VUSB_PROCESSORS = 'atmega32a', 'atmega328p', 'atmega328', 'attiny85' | 14 | VUSB_PROCESSORS = 'atmega32a', 'atmega328p', 'atmega328', 'attiny85' |
15 | |||
16 | # Common format strings | ||
17 | DATE_FORMAT = '%Y-%m-%d' | ||
18 | DATETIME_FORMAT = '%Y-%m-%d %H:%M:%S %Z' | ||
19 | TIME_FORMAT = '%H:%M:%S' | ||
diff --git a/lib/python/qmk/datetime.py b/lib/python/qmk/datetime.py new file mode 100644 index 000000000..4bffcc621 --- /dev/null +++ b/lib/python/qmk/datetime.py | |||
@@ -0,0 +1,29 @@ | |||
1 | """Functions to work with dates and times in a uniform way. | ||
2 | |||
3 | The results of these functions are cached for 5 seconds to provide uniform time strings across short running processes. Long running processes that need more precise timekeeping should not use these functions. | ||
4 | """ | ||
5 | from time import gmtime, strftime | ||
6 | |||
7 | from qmk.constants import DATE_FORMAT, DATETIME_FORMAT, TIME_FORMAT | ||
8 | from qmk.decorators import lru_cache | ||
9 | |||
10 | |||
11 | @lru_cache(timeout=5) | ||
12 | def current_date(): | ||
13 | """Returns the current time in UTZ as a formatted string. | ||
14 | """ | ||
15 | return strftime(DATE_FORMAT, gmtime()) | ||
16 | |||
17 | |||
18 | @lru_cache(timeout=5) | ||
19 | def current_datetime(): | ||
20 | """Returns the current time in UTZ as a formatted string. | ||
21 | """ | ||
22 | return strftime(DATETIME_FORMAT, gmtime()) | ||
23 | |||
24 | |||
25 | @lru_cache(timeout=5) | ||
26 | def current_time(): | ||
27 | """Returns the current time in UTZ as a formatted string. | ||
28 | """ | ||
29 | return strftime(TIME_FORMAT, gmtime()) | ||
diff --git a/lib/python/qmk/decorators.py b/lib/python/qmk/decorators.py index f8f2facb1..629402b09 100644 --- a/lib/python/qmk/decorators.py +++ b/lib/python/qmk/decorators.py | |||
@@ -2,6 +2,7 @@ | |||
2 | """ | 2 | """ |
3 | import functools | 3 | import functools |
4 | from pathlib import Path | 4 | from pathlib import Path |
5 | from time import monotonic | ||
5 | 6 | ||
6 | from milc import cli | 7 | from milc import cli |
7 | 8 | ||
@@ -84,3 +85,38 @@ def automagic_keymap(func): | |||
84 | return func(*args, **kwargs) | 85 | return func(*args, **kwargs) |
85 | 86 | ||
86 | return wrapper | 87 | return wrapper |
88 | |||
89 | |||
90 | def lru_cache(timeout=10, maxsize=128, typed=False): | ||
91 | """Least Recently Used Cache- cache the result of a function. | ||
92 | |||
93 | Args: | ||
94 | |||
95 | timeout | ||
96 | How many seconds to cache results for. | ||
97 | |||
98 | maxsize | ||
99 | The maximum size of the cache in bytes | ||
100 | |||
101 | typed | ||
102 | When `True` argument types will be taken into consideration, for example `3` and `3.0` will be treated as different keys. | ||
103 | """ | ||
104 | def wrapper_cache(func): | ||
105 | func = functools.lru_cache(maxsize=maxsize, typed=typed)(func) | ||
106 | func.expiration = monotonic() + timeout | ||
107 | |||
108 | @functools.wraps(func) | ||
109 | def wrapped_func(*args, **kwargs): | ||
110 | if monotonic() >= func.expiration: | ||
111 | func.expiration = monotonic() + timeout | ||
112 | |||
113 | func.cache_clear() | ||
114 | |||
115 | return func(*args, **kwargs) | ||
116 | |||
117 | wrapped_func.cache_info = func.cache_info | ||
118 | wrapped_func.cache_clear = func.cache_clear | ||
119 | |||
120 | return wrapped_func | ||
121 | |||
122 | return wrapper_cache | ||
diff --git a/lib/python/qmk/info.py b/lib/python/qmk/info.py index 0e540c00a..e92c3335b 100644 --- a/lib/python/qmk/info.py +++ b/lib/python/qmk/info.py | |||
@@ -9,6 +9,7 @@ from milc import cli | |||
9 | from qmk.constants import CHIBIOS_PROCESSORS, LUFA_PROCESSORS, VUSB_PROCESSORS | 9 | from qmk.constants import CHIBIOS_PROCESSORS, LUFA_PROCESSORS, VUSB_PROCESSORS |
10 | from qmk.c_parse import find_layouts | 10 | from qmk.c_parse import find_layouts |
11 | from qmk.keyboard import config_h, rules_mk | 11 | from qmk.keyboard import config_h, rules_mk |
12 | from qmk.keymap import list_keymaps | ||
12 | from qmk.makefile import parse_rules_mk_file | 13 | from qmk.makefile import parse_rules_mk_file |
13 | from qmk.math import compute | 14 | from qmk.math import compute |
14 | 15 | ||
@@ -25,14 +26,21 @@ def info_json(keyboard): | |||
25 | info_data = { | 26 | info_data = { |
26 | 'keyboard_name': str(keyboard), | 27 | 'keyboard_name': str(keyboard), |
27 | 'keyboard_folder': str(keyboard), | 28 | 'keyboard_folder': str(keyboard), |
29 | 'keymaps': {}, | ||
28 | 'layouts': {}, | 30 | 'layouts': {}, |
29 | 'maintainer': 'qmk', | 31 | 'maintainer': 'qmk', |
30 | } | 32 | } |
31 | 33 | ||
34 | # Populate the list of JSON keymaps | ||
35 | for keymap in list_keymaps(keyboard, c=False, fullpath=True): | ||
36 | info_data['keymaps'][keymap.name] = {'url': f'https://raw.githubusercontent.com/qmk/qmk_firmware/master/{keymap}/keymap.json'} | ||
37 | |||
38 | # Populate layout data | ||
32 | for layout_name, layout_json in _find_all_layouts(keyboard, rules).items(): | 39 | for layout_name, layout_json in _find_all_layouts(keyboard, rules).items(): |
33 | if not layout_name.startswith('LAYOUT_kc'): | 40 | if not layout_name.startswith('LAYOUT_kc'): |
34 | info_data['layouts'][layout_name] = layout_json | 41 | info_data['layouts'][layout_name] = layout_json |
35 | 42 | ||
43 | # Merge in the data from info.json, config.h, and rules.mk | ||
36 | info_data = merge_info_jsons(keyboard, info_data) | 44 | info_data = merge_info_jsons(keyboard, info_data) |
37 | info_data = _extract_config_h(info_data) | 45 | info_data = _extract_config_h(info_data) |
38 | info_data = _extract_rules_mk(info_data) | 46 | info_data = _extract_rules_mk(info_data) |
diff --git a/lib/python/qmk/keyboard.py b/lib/python/qmk/keyboard.py index d1f2a301d..9ebb2d77d 100644 --- a/lib/python/qmk/keyboard.py +++ b/lib/python/qmk/keyboard.py | |||
@@ -3,10 +3,30 @@ | |||
3 | from array import array | 3 | from array import array |
4 | from math import ceil | 4 | from math import ceil |
5 | from pathlib import Path | 5 | from pathlib import Path |
6 | import os | ||
7 | from glob import glob | ||
6 | 8 | ||
7 | from qmk.c_parse import parse_config_h_file | 9 | from qmk.c_parse import parse_config_h_file |
8 | from qmk.makefile import parse_rules_mk_file | 10 | from qmk.makefile import parse_rules_mk_file |
9 | 11 | ||
12 | base_path = os.path.join(os.getcwd(), "keyboards") + os.path.sep | ||
13 | |||
14 | |||
15 | def _find_name(path): | ||
16 | """Determine the keyboard name by stripping off the base_path and rules.mk. | ||
17 | """ | ||
18 | return path.replace(base_path, "").replace(os.path.sep + "rules.mk", "") | ||
19 | |||
20 | |||
21 | def list_keyboards(): | ||
22 | """Returns a list of all keyboards. | ||
23 | """ | ||
24 | # We avoid pathlib here because this is performance critical code. | ||
25 | kb_wildcard = os.path.join(base_path, "**", "rules.mk") | ||
26 | paths = [path for path in glob(kb_wildcard, recursive=True) if 'keymaps' not in path] | ||
27 | |||
28 | return sorted(map(_find_name, paths)) | ||
29 | |||
10 | 30 | ||
11 | def config_h(keyboard): | 31 | def config_h(keyboard): |
12 | """Parses all the config.h files for a keyboard. | 32 | """Parses all the config.h files for a keyboard. |
diff --git a/lib/python/qmk/keymap.py b/lib/python/qmk/keymap.py index 166697ee6..31c61ae6a 100644 --- a/lib/python/qmk/keymap.py +++ b/lib/python/qmk/keymap.py | |||
@@ -29,33 +29,37 @@ __KEYMAP_GOES_HERE__ | |||
29 | """ | 29 | """ |
30 | 30 | ||
31 | 31 | ||
32 | def template(keyboard, type='c'): | 32 | def template_json(keyboard): |
33 | """Returns the `keymap.c` or `keymap.json` template for a keyboard. | 33 | """Returns a `keymap.json` template for a keyboard. |
34 | 34 | ||
35 | If a template exists in `keyboards/<keyboard>/templates/keymap.c` that | 35 | If a template exists in `keyboards/<keyboard>/templates/keymap.json` that text will be used instead of an empty dictionary. |
36 | text will be used instead of `DEFAULT_KEYMAP_C`. | ||
37 | |||
38 | If a template exists in `keyboards/<keyboard>/templates/keymap.json` that | ||
39 | text will be used instead of an empty dictionary. | ||
40 | 36 | ||
41 | Args: | 37 | Args: |
42 | keyboard | 38 | keyboard |
43 | The keyboard to return a template for. | 39 | The keyboard to return a template for. |
40 | """ | ||
41 | template_file = Path('keyboards/%s/templates/keymap.json' % keyboard) | ||
42 | template = {'keyboard': keyboard} | ||
43 | if template_file.exists(): | ||
44 | template.update(json.loads(template_file.read_text())) | ||
45 | |||
46 | return template | ||
47 | |||
44 | 48 | ||
45 | type | 49 | def template_c(keyboard): |
46 | 'json' for `keymap.json` and 'c' (or anything else) for `keymap.c` | 50 | """Returns a `keymap.c` template for a keyboard. |
51 | |||
52 | If a template exists in `keyboards/<keyboard>/templates/keymap.c` that text will be used instead of an empty dictionary. | ||
53 | |||
54 | Args: | ||
55 | keyboard | ||
56 | The keyboard to return a template for. | ||
47 | """ | 57 | """ |
48 | if type == 'json': | 58 | template_file = Path('keyboards/%s/templates/keymap.c' % keyboard) |
49 | template_file = Path('keyboards/%s/templates/keymap.json' % keyboard) | 59 | if template_file.exists(): |
50 | template = {'keyboard': keyboard} | 60 | template = template_file.read_text() |
51 | if template_file.exists(): | ||
52 | template.update(json.loads(template_file.read_text())) | ||
53 | else: | 61 | else: |
54 | template_file = Path('keyboards/%s/templates/keymap.c' % keyboard) | 62 | template = DEFAULT_KEYMAP_C |
55 | if template_file.exists(): | ||
56 | template = template_file.read_text() | ||
57 | else: | ||
58 | template = DEFAULT_KEYMAP_C | ||
59 | 63 | ||
60 | return template | 64 | return template |
61 | 65 | ||
@@ -69,15 +73,65 @@ def _strip_any(keycode): | |||
69 | return keycode | 73 | return keycode |
70 | 74 | ||
71 | 75 | ||
72 | def is_keymap_dir(keymap): | 76 | def is_keymap_dir(keymap, c=True, json=True, additional_files=None): |
73 | """Return True if Path object `keymap` has a keymap file inside. | 77 | """Return True if Path object `keymap` has a keymap file inside. |
78 | |||
79 | Args: | ||
80 | keymap | ||
81 | A Path() object for the keymap directory you want to check. | ||
82 | |||
83 | c | ||
84 | When true include `keymap.c` keymaps. | ||
85 | |||
86 | json | ||
87 | When true include `keymap.json` keymaps. | ||
88 | |||
89 | additional_files | ||
90 | A sequence of additional filenames to check against to determine if a directory is a keymap. All files must exist for a match to happen. For example, if you want to match a C keymap with both a `config.h` and `rules.mk` file: `is_keymap_dir(keymap_dir, json=False, additional_files=['config.h', 'rules.mk'])` | ||
74 | """ | 91 | """ |
75 | for file in ('keymap.c', 'keymap.json'): | 92 | files = [] |
93 | |||
94 | if c: | ||
95 | files.append('keymap.c') | ||
96 | |||
97 | if json: | ||
98 | files.append('keymap.json') | ||
99 | |||
100 | for file in files: | ||
76 | if (keymap / file).is_file(): | 101 | if (keymap / file).is_file(): |
102 | if additional_files: | ||
103 | for file in additional_files: | ||
104 | if not (keymap / file).is_file(): | ||
105 | return False | ||
106 | |||
77 | return True | 107 | return True |
78 | 108 | ||
79 | 109 | ||
80 | def generate(keyboard, layout, layers, type='c', keymap=None): | 110 | def generate_json(keymap, keyboard, layout, layers): |
111 | """Returns a `keymap.json` for the specified keyboard, layout, and layers. | ||
112 | |||
113 | Args: | ||
114 | keymap | ||
115 | A name for this keymap. | ||
116 | |||
117 | keyboard | ||
118 | The name of the keyboard. | ||
119 | |||
120 | layout | ||
121 | The LAYOUT macro this keymap uses. | ||
122 | |||
123 | layers | ||
124 | An array of arrays describing the keymap. Each item in the inner array should be a string that is a valid QMK keycode. | ||
125 | """ | ||
126 | new_keymap = template_json(keyboard) | ||
127 | new_keymap['keymap'] = keymap | ||
128 | new_keymap['layout'] = layout | ||
129 | new_keymap['layers'] = layers | ||
130 | |||
131 | return new_keymap | ||
132 | |||
133 | |||
134 | def generate_c(keyboard, layout, layers): | ||
81 | """Returns a `keymap.c` or `keymap.json` for the specified keyboard, layout, and layers. | 135 | """Returns a `keymap.c` or `keymap.json` for the specified keyboard, layout, and layers. |
82 | 136 | ||
83 | Args: | 137 | Args: |
@@ -89,33 +143,33 @@ def generate(keyboard, layout, layers, type='c', keymap=None): | |||
89 | 143 | ||
90 | layers | 144 | layers |
91 | An array of arrays describing the keymap. Each item in the inner array should be a string that is a valid QMK keycode. | 145 | An array of arrays describing the keymap. Each item in the inner array should be a string that is a valid QMK keycode. |
92 | |||
93 | type | ||
94 | 'json' for `keymap.json` and 'c' (or anything else) for `keymap.c` | ||
95 | """ | 146 | """ |
96 | new_keymap = template(keyboard, type) | 147 | new_keymap = template_c(keyboard) |
97 | if type == 'json': | 148 | layer_txt = [] |
98 | new_keymap['keymap'] = keymap | 149 | for layer_num, layer in enumerate(layers): |
99 | new_keymap['layout'] = layout | 150 | if layer_num != 0: |
100 | new_keymap['layers'] = layers | 151 | layer_txt[-1] = layer_txt[-1] + ',' |
101 | else: | 152 | layer = map(_strip_any, layer) |
102 | layer_txt = [] | 153 | layer_keys = ', '.join(layer) |
103 | for layer_num, layer in enumerate(layers): | 154 | layer_txt.append('\t[%s] = %s(%s)' % (layer_num, layout, layer_keys)) |
104 | if layer_num != 0: | 155 | |
105 | layer_txt[-1] = layer_txt[-1] + ',' | 156 | keymap = '\n'.join(layer_txt) |
157 | new_keymap = new_keymap.replace('__KEYMAP_GOES_HERE__', keymap) | ||
106 | 158 | ||
107 | layer = map(_strip_any, layer) | 159 | return new_keymap |
108 | layer_keys = ', '.join(layer) | ||
109 | layer_txt.append('\t[%s] = %s(%s)' % (layer_num, layout, layer_keys)) | ||
110 | 160 | ||
111 | keymap = '\n'.join(layer_txt) | ||
112 | new_keymap = new_keymap.replace('__KEYMAP_GOES_HERE__', keymap) | ||
113 | 161 | ||
114 | return new_keymap | 162 | def write_file(keymap_filename, keymap_content): |
163 | keymap_filename.parent.mkdir(parents=True, exist_ok=True) | ||
164 | keymap_filename.write_text(keymap_content) | ||
115 | 165 | ||
166 | cli.log.info('Wrote keymap to {fg_cyan}%s', keymap_filename) | ||
167 | |||
168 | return keymap_filename | ||
116 | 169 | ||
117 | def write(keyboard, keymap, layout, layers, type='c'): | 170 | |
118 | """Generate the `keymap.c` and write it to disk. | 171 | def write_json(keyboard, keymap, layout, layers): |
172 | """Generate the `keymap.json` and write it to disk. | ||
119 | 173 | ||
120 | Returns the filename written to. | 174 | Returns the filename written to. |
121 | 175 | ||
@@ -131,23 +185,36 @@ def write(keyboard, keymap, layout, layers, type='c'): | |||
131 | 185 | ||
132 | layers | 186 | layers |
133 | An array of arrays describing the keymap. Each item in the inner array should be a string that is a valid QMK keycode. | 187 | An array of arrays describing the keymap. Each item in the inner array should be a string that is a valid QMK keycode. |
134 | |||
135 | type | ||
136 | 'json' for `keymap.json` and 'c' (or anything else) for `keymap.c` | ||
137 | """ | 188 | """ |
138 | keymap_content = generate(keyboard, layout, layers, type) | 189 | keymap_json = generate_json(keyboard, keymap, layout, layers) |
139 | if type == 'json': | 190 | keymap_content = json.dumps(keymap_json) |
140 | keymap_file = qmk.path.keymap(keyboard) / keymap / 'keymap.json' | 191 | keymap_file = qmk.path.keymap(keyboard) / keymap / 'keymap.json' |
141 | keymap_content = json.dumps(keymap_content) | 192 | |
142 | else: | 193 | return write_file(keymap_file, keymap_content) |
143 | keymap_file = qmk.path.keymap(keyboard) / keymap / 'keymap.c' | 194 | |
195 | |||
196 | def write(keyboard, keymap, layout, layers): | ||
197 | """Generate the `keymap.c` and write it to disk. | ||
198 | |||
199 | Returns the filename written to. | ||
200 | |||
201 | Args: | ||
202 | keyboard | ||
203 | The name of the keyboard | ||
144 | 204 | ||
145 | keymap_file.parent.mkdir(parents=True, exist_ok=True) | 205 | keymap |
146 | keymap_file.write_text(keymap_content) | 206 | The name of the keymap |
147 | 207 | ||
148 | cli.log.info('Wrote keymap to {fg_cyan}%s', keymap_file) | 208 | layout |
209 | The LAYOUT macro this keymap uses. | ||
210 | |||
211 | layers | ||
212 | An array of arrays describing the keymap. Each item in the inner array should be a string that is a valid QMK keycode. | ||
213 | """ | ||
214 | keymap_content = generate_c(keyboard, layout, layers) | ||
215 | keymap_file = qmk.path.keymap(keyboard) / keymap / 'keymap.c' | ||
149 | 216 | ||
150 | return keymap_file | 217 | return write_file(keymap_file, keymap_content) |
151 | 218 | ||
152 | 219 | ||
153 | def locate_keymap(keyboard, keymap): | 220 | def locate_keymap(keyboard, keymap): |
@@ -189,38 +256,58 @@ def locate_keymap(keyboard, keymap): | |||
189 | return community_layout / 'keymap.c' | 256 | return community_layout / 'keymap.c' |
190 | 257 | ||
191 | 258 | ||
192 | def list_keymaps(keyboard): | 259 | def list_keymaps(keyboard, c=True, json=True, additional_files=None, fullpath=False): |
193 | """ List the available keymaps for a keyboard. | 260 | """List the available keymaps for a keyboard. |
194 | 261 | ||
195 | Args: | 262 | Args: |
196 | keyboard: the keyboards full name with vendor and revision if necessary, example: clueboard/66/rev3 | 263 | keyboard |
264 | The keyboards full name with vendor and revision if necessary, example: clueboard/66/rev3 | ||
265 | |||
266 | c | ||
267 | When true include `keymap.c` keymaps. | ||
268 | |||
269 | json | ||
270 | When true include `keymap.json` keymaps. | ||
271 | |||
272 | additional_files | ||
273 | A sequence of additional filenames to check against to determine if a directory is a keymap. All files must exist for a match to happen. For example, if you want to match a C keymap with both a `config.h` and `rules.mk` file: `is_keymap_dir(keymap_dir, json=False, additional_files=['config.h', 'rules.mk'])` | ||
274 | |||
275 | fullpath | ||
276 | When set to True the full path of the keymap relative to the `qmk_firmware` root will be provided. | ||
197 | 277 | ||
198 | Returns: | 278 | Returns: |
199 | a set with the names of the available keymaps | 279 | a sorted list of valid keymap names. |
200 | """ | 280 | """ |
201 | # parse all the rules.mk files for the keyboard | 281 | # parse all the rules.mk files for the keyboard |
202 | rules = rules_mk(keyboard) | 282 | rules = rules_mk(keyboard) |
203 | names = set() | 283 | names = set() |
204 | 284 | ||
205 | if rules: | 285 | if rules: |
206 | # qmk_firmware/keyboards | ||
207 | keyboards_dir = Path('keyboards') | 286 | keyboards_dir = Path('keyboards') |
208 | # path to the keyboard's directory | ||
209 | kb_path = keyboards_dir / keyboard | 287 | kb_path = keyboards_dir / keyboard |
288 | |||
210 | # walk up the directory tree until keyboards_dir | 289 | # walk up the directory tree until keyboards_dir |
211 | # and collect all directories' name with keymap.c file in it | 290 | # and collect all directories' name with keymap.c file in it |
212 | while kb_path != keyboards_dir: | 291 | while kb_path != keyboards_dir: |
213 | keymaps_dir = kb_path / "keymaps" | 292 | keymaps_dir = kb_path / "keymaps" |
214 | if keymaps_dir.exists(): | 293 | |
215 | names = names.union([keymap.name for keymap in keymaps_dir.iterdir() if is_keymap_dir(keymap)]) | 294 | if keymaps_dir.is_dir(): |
295 | for keymap in keymaps_dir.iterdir(): | ||
296 | if is_keymap_dir(keymap, c, json, additional_files): | ||
297 | keymap = keymap if fullpath else keymap.name | ||
298 | names.add(keymap) | ||
299 | |||
216 | kb_path = kb_path.parent | 300 | kb_path = kb_path.parent |
217 | 301 | ||
218 | # if community layouts are supported, get them | 302 | # if community layouts are supported, get them |
219 | if "LAYOUTS" in rules: | 303 | if "LAYOUTS" in rules: |
220 | for layout in rules["LAYOUTS"].split(): | 304 | for layout in rules["LAYOUTS"].split(): |
221 | cl_path = Path('layouts/community') / layout | 305 | cl_path = Path('layouts/community') / layout |
222 | if cl_path.exists(): | 306 | if cl_path.is_dir(): |
223 | names = names.union([keymap.name for keymap in cl_path.iterdir() if is_keymap_dir(keymap)]) | 307 | for keymap in cl_path.iterdir(): |
308 | if is_keymap_dir(keymap, c, json, additional_files): | ||
309 | keymap = keymap if fullpath else keymap.name | ||
310 | names.add(keymap) | ||
224 | 311 | ||
225 | return sorted(names) | 312 | return sorted(names) |
226 | 313 | ||
diff --git a/lib/python/qmk/tests/test_qmk_keymap.py b/lib/python/qmk/tests/test_qmk_keymap.py index 7ef708e0d..f1ecf2937 100644 --- a/lib/python/qmk/tests/test_qmk_keymap.py +++ b/lib/python/qmk/tests/test_qmk_keymap.py | |||
@@ -1,33 +1,33 @@ | |||
1 | import qmk.keymap | 1 | import qmk.keymap |
2 | 2 | ||
3 | 3 | ||
4 | def test_template_onekey_proton_c(): | 4 | def test_template_c_onekey_proton_c(): |
5 | templ = qmk.keymap.template('handwired/onekey/proton_c') | 5 | templ = qmk.keymap.template_c('handwired/onekey/proton_c') |
6 | assert templ == qmk.keymap.DEFAULT_KEYMAP_C | 6 | assert templ == qmk.keymap.DEFAULT_KEYMAP_C |
7 | 7 | ||
8 | 8 | ||
9 | def test_template_onekey_proton_c_json(): | 9 | def test_template_json_onekey_proton_c(): |
10 | templ = qmk.keymap.template('handwired/onekey/proton_c', type='json') | 10 | templ = qmk.keymap.template_json('handwired/onekey/proton_c') |
11 | assert templ == {'keyboard': 'handwired/onekey/proton_c'} | 11 | assert templ == {'keyboard': 'handwired/onekey/proton_c'} |
12 | 12 | ||
13 | 13 | ||
14 | def test_template_onekey_pytest(): | 14 | def test_template_c_onekey_pytest(): |
15 | templ = qmk.keymap.template('handwired/onekey/pytest') | 15 | templ = qmk.keymap.template_c('handwired/onekey/pytest') |
16 | assert templ == '#include QMK_KEYBOARD_H\nconst uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {__KEYMAP_GOES_HERE__};\n' | 16 | assert templ == '#include QMK_KEYBOARD_H\nconst uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {__KEYMAP_GOES_HERE__};\n' |
17 | 17 | ||
18 | 18 | ||
19 | def test_template_onekey_pytest_json(): | 19 | def test_template_json_onekey_pytest(): |
20 | templ = qmk.keymap.template('handwired/onekey/pytest', type='json') | 20 | templ = qmk.keymap.template_json('handwired/onekey/pytest') |
21 | assert templ == {'keyboard': 'handwired/onekey/pytest', "documentation": "This file is a keymap.json file for handwired/onekey/pytest"} | 21 | assert templ == {'keyboard': 'handwired/onekey/pytest', "documentation": "This file is a keymap.json file for handwired/onekey/pytest"} |
22 | 22 | ||
23 | 23 | ||
24 | def test_generate_onekey_pytest(): | 24 | def test_generate_c_onekey_pytest(): |
25 | templ = qmk.keymap.generate('handwired/onekey/pytest', 'LAYOUT', [['KC_A']]) | 25 | templ = qmk.keymap.generate_c('handwired/onekey/pytest', 'LAYOUT', [['KC_A']]) |
26 | assert templ == '#include QMK_KEYBOARD_H\nconst uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {\t[0] = LAYOUT(KC_A)};\n' | 26 | assert templ == '#include QMK_KEYBOARD_H\nconst uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {\t[0] = LAYOUT(KC_A)};\n' |
27 | 27 | ||
28 | 28 | ||
29 | def test_generate_onekey_pytest_json(): | 29 | def test_generate_json_onekey_pytest(): |
30 | templ = qmk.keymap.generate('handwired/onekey/pytest', 'LAYOUT', [['KC_A']], type='json', keymap='default') | 30 | templ = qmk.keymap.generate_json('default', 'handwired/onekey/pytest', 'LAYOUT', [['KC_A']]) |
31 | assert templ == {"keyboard": "handwired/onekey/pytest", "documentation": "This file is a keymap.json file for handwired/onekey/pytest", "keymap": "default", "layout": "LAYOUT", "layers": [["KC_A"]]} | 31 | assert templ == {"keyboard": "handwired/onekey/pytest", "documentation": "This file is a keymap.json file for handwired/onekey/pytest", "keymap": "default", "layout": "LAYOUT", "layers": [["KC_A"]]} |
32 | 32 | ||
33 | 33 | ||