aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorskullydazed <skullydazed@users.noreply.github.com>2020-04-18 13:00:56 -0700
committerGitHub <noreply@github.com>2020-04-18 22:00:56 +0200
commit66d94dc22af4fccae2af073c512662ce7eba7d98 (patch)
treea720968b0f1951cc2ec920da373701d308f04d88
parent5a8f59503e41923030249561e9ef56be62de3efa (diff)
downloadqmk_firmware-66d94dc22af4fccae2af073c512662ce7eba7d98.tar.gz
qmk_firmware-66d94dc22af4fccae2af073c512662ce7eba7d98.zip
Move everything to Python 3.6 (#8835)
-rwxr-xr-xbin/qmk2
-rw-r--r--docs/cli.md4
-rw-r--r--docs/cli_development.md6
-rw-r--r--docs/coding_conventions_python.md4
-rw-r--r--lib/python/qmk/cli/__init__.py7
-rw-r--r--lib/python/qmk/cli/cformat.py5
-rwxr-xr-xlib/python/qmk/cli/doctor.py11
-rwxr-xr-xlib/python/qmk/cli/json2c.py8
-rwxr-xr-xlib/python/qmk/cli/kle2json.py8
-rwxr-xr-xlib/python/qmk/cli/new/keymap.py2
-rw-r--r--lib/python/qmk/keymap.py5
11 files changed, 30 insertions, 32 deletions
diff --git a/bin/qmk b/bin/qmk
index 750ff2bdb..801852d4e 100755
--- a/bin/qmk
+++ b/bin/qmk
@@ -35,7 +35,7 @@ def _check_modules(requirements):
35 35
36 if not find_spec(module['import']): 36 if not find_spec(module['import']):
37 print('Could not find module %s!' % module['name']) 37 print('Could not find module %s!' % module['name'])
38 print('Please run `python3 -m pip install -r %s` to install required python dependencies.' % str(qmk_dir / requirements)) 38 print('Please run `python3 -m pip install -r %s` to install required python dependencies.' % (qmk_dir / requirements,))
39 if developer: 39 if developer:
40 print('You can also turn off developer mode: qmk config user.developer=None') 40 print('You can also turn off developer mode: qmk config user.developer=None')
41 print() 41 print()
diff --git a/docs/cli.md b/docs/cli.md
index 760fe1cdb..01641bd8b 100644
--- a/docs/cli.md
+++ b/docs/cli.md
@@ -6,7 +6,7 @@ The QMK CLI makes building and working with QMK keyboards easier. We have provid
6 6
7### Requirements :id=requirements 7### Requirements :id=requirements
8 8
9The CLI requires Python 3.5 or greater. We try to keep the number of requirements small but you will also need to install the packages listed in [`requirements.txt`](https://github.com/qmk/qmk_firmware/blob/master/requirements.txt). These are installed automatically when you install the QMK CLI. 9QMK requires Python 3.6 or greater. We try to keep the number of requirements small but you will also need to install the packages listed in [`requirements.txt`](https://github.com/qmk/qmk_firmware/blob/master/requirements.txt). These are installed automatically when you install the QMK CLI.
10 10
11### Install Using Homebrew (macOS, some Linux) :id=install-using-homebrew 11### Install Using Homebrew (macOS, some Linux) :id=install-using-homebrew
12 12
@@ -21,7 +21,7 @@ qmk setup # This will clone `qmk/qmk_firmware` and optionally set up your build
21 21
22### Install Using easy_install or pip :id=install-using-easy_install-or-pip 22### Install Using easy_install or pip :id=install-using-easy_install-or-pip
23 23
24If your system is not listed above you can install QMK manually. First ensure that you have python 3.5 (or later) installed and have installed pip. Then install QMK with this command: 24If your system is not listed above you can install QMK manually. First ensure that you have python 3.6 (or later) installed and have installed pip. Then install QMK with this command:
25 25
26``` 26```
27pip3 install qmk 27pip3 install qmk
diff --git a/docs/cli_development.md b/docs/cli_development.md
index 2a967de4a..af86686c0 100644
--- a/docs/cli_development.md
+++ b/docs/cli_development.md
@@ -44,7 +44,7 @@ def hello(cli):
44 44
45First we import the `cli` object from `milc`. This is how we interact with the user and control the script's behavior. We use `@cli.argument()` to define a command line flag, `--name`. This also creates a configuration variable named `hello.name` (and the corresponding `user.name`) which the user can set so they don't have to specify the argument. The `cli.subcommand()` decorator designates this function as a subcommand. The name of the subcommand will be taken from the name of the function. 45First we import the `cli` object from `milc`. This is how we interact with the user and control the script's behavior. We use `@cli.argument()` to define a command line flag, `--name`. This also creates a configuration variable named `hello.name` (and the corresponding `user.name`) which the user can set so they don't have to specify the argument. The `cli.subcommand()` decorator designates this function as a subcommand. The name of the subcommand will be taken from the name of the function.
46 46
47Once inside our function we find a typical "Hello, World!" program. We use `cli.log` to access the underlying [Logger Object](https://docs.python.org/3.5/library/logging.html#logger-objects), whose behavior is user controllable. We also access the value for name supplied by the user as `cli.config.hello.name`. The value for `cli.config.hello.name` will be determined by looking at the `--name` argument supplied by the user, if not provided it will use the value in the `qmk.ini` config file, and if neither of those is provided it will fall back to the default supplied in the `cli.argument()` decorator. 47Once inside our function we find a typical "Hello, World!" program. We use `cli.log` to access the underlying [Logger Object](https://docs.python.org/3.6/library/logging.html#logger-objects), whose behavior is user controllable. We also access the value for name supplied by the user as `cli.config.hello.name`. The value for `cli.config.hello.name` will be determined by looking at the `--name` argument supplied by the user, if not provided it will use the value in the `qmk.ini` config file, and if neither of those is provided it will fall back to the default supplied in the `cli.argument()` decorator.
48 48
49# User Interaction 49# User Interaction
50 50
@@ -56,13 +56,13 @@ There are two main methods for outputting text in a subcommand- `cli.log` and `c
56 56
57You can use special tokens to colorize your text, to make it easier to understand the output of your program. See [Colorizing Text](#colorizing-text) below. 57You can use special tokens to colorize your text, to make it easier to understand the output of your program. See [Colorizing Text](#colorizing-text) below.
58 58
59Both of these methods support built-in string formatting using python's [printf style string format operations](https://docs.python.org/3.5/library/stdtypes.html#old-string-formatting). You can use tokens such as `%s` and `%d` within your text strings then pass the values as arguments. See our Hello, World program above for an example. 59Both of these methods support built-in string formatting using python's [printf style string format operations](https://docs.python.org/3.6/library/stdtypes.html#old-string-formatting). You can use tokens such as `%s` and `%d` within your text strings then pass the values as arguments. See our Hello, World program above for an example.
60 60
61You should never use the format operator (`%`) directly, always pass values as arguments. 61You should never use the format operator (`%`) directly, always pass values as arguments.
62 62
63### Logging (`cli.log`) 63### Logging (`cli.log`)
64 64
65The `cli.log` object gives you access to a [Logger Object](https://docs.python.org/3.5/library/logging.html#logger-objects). We have configured our log output to show the user a nice emoji for each log level (or the log level name if their terminal does not support unicode.) This way the user can tell at a glance which messages are most important when something goes wrong. 65The `cli.log` object gives you access to a [Logger Object](https://docs.python.org/3.6/library/logging.html#logger-objects). We have configured our log output to show the user a nice emoji for each log level (or the log level name if their terminal does not support unicode.) This way the user can tell at a glance which messages are most important when something goes wrong.
66 66
67The default log level is `INFO`. If the user runs `qmk -v <subcommand>` the default log level will be set to `DEBUG`. 67The default log level is `INFO`. If the user runs `qmk -v <subcommand>` the default log level will be set to `DEBUG`.
68 68
diff --git a/docs/coding_conventions_python.md b/docs/coding_conventions_python.md
index 1aefc044e..47dff7f8e 100644
--- a/docs/coding_conventions_python.md
+++ b/docs/coding_conventions_python.md
@@ -2,7 +2,7 @@
2 2
3Most of our style follows PEP8 with some local modifications to make things less nit-picky. 3Most of our style follows PEP8 with some local modifications to make things less nit-picky.
4 4
5* We target Python 3.5 for compatability with all supported platforms. 5* We target Python 3.6 for compatability with all supported platforms.
6* We indent using four (4) spaces (soft tabs) 6* We indent using four (4) spaces (soft tabs)
7* We encourage liberal use of comments 7* We encourage liberal use of comments
8 * Think of them as a story describing the feature 8 * Think of them as a story describing the feature
@@ -317,7 +317,7 @@ At the time of this writing our tests are not very comprehensive. Looking at the
317 317
318## Integration Tests 318## Integration Tests
319 319
320Integration tests can be found in `lib/python/qmk/tests/test_cli_commands.py`. This is where CLI commands are actually run and their overall behavior is verified. We use [`subprocess`](https://docs.python.org/3.5/library/subprocess.html#module-subprocess) to launch each CLI command and a combination of checking output and returncode to determine if the right thing happened. 320Integration tests can be found in `lib/python/qmk/tests/test_cli_commands.py`. This is where CLI commands are actually run and their overall behavior is verified. We use [`subprocess`](https://docs.python.org/3.6/library/subprocess.html#module-subprocess) to launch each CLI command and a combination of checking output and returncode to determine if the right thing happened.
321 321
322## Unit Tests 322## Unit Tests
323 323
diff --git a/lib/python/qmk/cli/__init__.py b/lib/python/qmk/cli/__init__.py
index eb524217c..394a1353b 100644
--- a/lib/python/qmk/cli/__init__.py
+++ b/lib/python/qmk/cli/__init__.py
@@ -2,6 +2,8 @@
2 2
3We list each subcommand here explicitly because all the reliable ways of searching for modules are slow and delay startup. 3We list each subcommand here explicitly because all the reliable ways of searching for modules are slow and delay startup.
4""" 4"""
5import sys
6
5from milc import cli 7from milc import cli
6 8
7from . import cformat 9from . import cformat
@@ -19,5 +21,6 @@ from . import new
19from . import pyformat 21from . import pyformat
20from . import pytest 22from . import pytest
21 23
22if not hasattr(cli, 'config_source'): 24if sys.version_info[0] != 3 or sys.version_info[1] < 6:
23 cli.log.warning("Your QMK CLI is out of date. Please upgrade with `pip3 install --upgrade qmk` or by using your package manager.") 25 cli.log.error('Your Python is too old! Please upgrade to Python 3.6 or later.')
26 exit(127)
diff --git a/lib/python/qmk/cli/cformat.py b/lib/python/qmk/cli/cformat.py
index 536ee30fd..0cd8b6192 100644
--- a/lib/python/qmk/cli/cformat.py
+++ b/lib/python/qmk/cli/cformat.py
@@ -22,9 +22,8 @@ def cformat_run(files, all_files):
22 cli.log.warn('No changes detected. Use "qmk cformat -a" to format all files') 22 cli.log.warn('No changes detected. Use "qmk cformat -a" to format all files')
23 return False 23 return False
24 if files and all_files: 24 if files and all_files:
25 cli.log.warning('Filenames passed with -a, only formatting: %s', ','.join(cli.args.files)) 25 cli.log.warning('Filenames passed with -a, only formatting: %s', ','.join(files))
26 # 3.6+: Can remove the str casting, python will cast implicitly 26 subprocess.run(clang_format + [file for file in files], check=True)
27 subprocess.run(clang_format + [str(file) for file in files], check=True)
28 cli.log.info('Successfully formatted the C code.') 27 cli.log.info('Successfully formatted the C code.')
29 28
30 except subprocess.CalledProcessError: 29 except subprocess.CalledProcessError:
diff --git a/lib/python/qmk/cli/doctor.py b/lib/python/qmk/cli/doctor.py
index 3c74fae69..3c4624837 100755
--- a/lib/python/qmk/cli/doctor.py
+++ b/lib/python/qmk/cli/doctor.py
@@ -135,16 +135,15 @@ def check_udev_rules():
135 } 135 }
136 136
137 if udev_dir.exists(): 137 if udev_dir.exists():
138 udev_rules = [str(rule_file) for rule_file in udev_dir.glob('*.rules')] 138 udev_rules = [rule_file for rule_file in udev_dir.glob('*.rules')]
139 current_rules = set() 139 current_rules = set()
140 140
141 # Collect all rules from the config files 141 # Collect all rules from the config files
142 for rule_file in udev_rules: 142 for rule_file in udev_rules:
143 with open(rule_file, "r") as fd: 143 for line in rule_file.read_text().split('\n'):
144 for line in fd.readlines(): 144 line = line.strip()
145 line = line.strip() 145 if not line.startswith("#") and len(line):
146 if not line.startswith("#") and len(line): 146 current_rules.add(line)
147 current_rules.add(line)
148 147
149 # Check if the desired rules are among the currently present rules 148 # Check if the desired rules are among the currently present rules
150 for bootloader, rules in desired_rules.items(): 149 for bootloader, rules in desired_rules.items():
diff --git a/lib/python/qmk/cli/json2c.py b/lib/python/qmk/cli/json2c.py
index 46c4d04bb..521840507 100755
--- a/lib/python/qmk/cli/json2c.py
+++ b/lib/python/qmk/cli/json2c.py
@@ -10,29 +10,27 @@ import qmk.path
10 10
11@cli.argument('-o', '--output', arg_only=True, type=qmk.path.normpath, help='File to write to') 11@cli.argument('-o', '--output', arg_only=True, type=qmk.path.normpath, help='File to write to')
12@cli.argument('-q', '--quiet', arg_only=True, action='store_true', help="Quiet mode, only output error messages") 12@cli.argument('-q', '--quiet', arg_only=True, action='store_true', help="Quiet mode, only output error messages")
13@cli.argument('filename', arg_only=True, help='Configurator JSON file') 13@cli.argument('filename', type=qmk.path.normpath, arg_only=True, help='Configurator JSON file')
14@cli.subcommand('Creates a keymap.c from a QMK Configurator export.') 14@cli.subcommand('Creates a keymap.c from a QMK Configurator export.')
15def json2c(cli): 15def json2c(cli):
16 """Generate a keymap.c from a configurator export. 16 """Generate a keymap.c from a configurator export.
17 17
18 This command uses the `qmk.keymap` module to generate a keymap.c from a configurator export. The generated keymap is written to stdout, or to a file if -o is provided. 18 This command uses the `qmk.keymap` module to generate a keymap.c from a configurator export. The generated keymap is written to stdout, or to a file if -o is provided.
19 """ 19 """
20 cli.args.filename = qmk.path.normpath(cli.args.filename)
21
22 # Error checking 20 # Error checking
23 if not cli.args.filename.exists(): 21 if not cli.args.filename.exists():
24 cli.log.error('JSON file does not exist!') 22 cli.log.error('JSON file does not exist!')
25 cli.print_usage() 23 cli.print_usage()
26 exit(1) 24 exit(1)
27 25
28 if str(cli.args.filename) == '-': 26 if cli.args.filename.name == '-':
29 # TODO(skullydazed/anyone): Read file contents from STDIN 27 # TODO(skullydazed/anyone): Read file contents from STDIN
30 cli.log.error('Reading from STDIN is not (yet) supported.') 28 cli.log.error('Reading from STDIN is not (yet) supported.')
31 cli.print_usage() 29 cli.print_usage()
32 exit(1) 30 exit(1)
33 31
34 # Environment processing 32 # Environment processing
35 if cli.args.output == ('-'): 33 if cli.args.output.name == ('-'):
36 cli.args.output = None 34 cli.args.output = None
37 35
38 # Parse the configurator json 36 # Parse the configurator json
diff --git a/lib/python/qmk/cli/kle2json.py b/lib/python/qmk/cli/kle2json.py
index 3ed6594e0..5268462f9 100755
--- a/lib/python/qmk/cli/kle2json.py
+++ b/lib/python/qmk/cli/kle2json.py
@@ -37,12 +37,12 @@ def kle2json(cli):
37 file_path = Path(os.environ['ORIG_CWD'], cli.args.filename) 37 file_path = Path(os.environ['ORIG_CWD'], cli.args.filename)
38 # Check for valid file_path for more graceful failure 38 # Check for valid file_path for more graceful failure
39 if not file_path.exists(): 39 if not file_path.exists():
40 return cli.log.error('File {fg_cyan}%s{style_reset_all} was not found.', str(file_path)) 40 return cli.log.error('File {fg_cyan}%s{style_reset_all} was not found.', file_path)
41 out_path = file_path.parent 41 out_path = file_path.parent
42 raw_code = file_path.open().read() 42 raw_code = file_path.open().read()
43 # Check if info.json exists, allow overwrite with force 43 # Check if info.json exists, allow overwrite with force
44 if Path(out_path, "info.json").exists() and not cli.args.force: 44 if Path(out_path, "info.json").exists() and not cli.args.force:
45 cli.log.error('File {fg_cyan}%s/info.json{style_reset_all} already exists, use -f or --force to overwrite.', str(out_path)) 45 cli.log.error('File {fg_cyan}%s/info.json{style_reset_all} already exists, use -f or --force to overwrite.', out_path)
46 return False 46 return False
47 try: 47 try:
48 # Convert KLE raw to x/y coordinates (using kle2xy package from skullydazed) 48 # Convert KLE raw to x/y coordinates (using kle2xy package from skullydazed)
@@ -69,7 +69,7 @@ def kle2json(cli):
69 # Replace layout in keyboard json 69 # Replace layout in keyboard json
70 keyboard = keyboard.replace('"LAYOUT_JSON_HERE"', layout) 70 keyboard = keyboard.replace('"LAYOUT_JSON_HERE"', layout)
71 # Write our info.json 71 # Write our info.json
72 file = open(str(out_path) + "/info.json", "w") 72 file = open(out_path + "/info.json", "w")
73 file.write(keyboard) 73 file.write(keyboard)
74 file.close() 74 file.close()
75 cli.log.info('Wrote out {fg_cyan}%s/info.json', str(out_path)) 75 cli.log.info('Wrote out {fg_cyan}%s/info.json', out_path)
diff --git a/lib/python/qmk/cli/new/keymap.py b/lib/python/qmk/cli/new/keymap.py
index 5ae262856..474fe7974 100755
--- a/lib/python/qmk/cli/new/keymap.py
+++ b/lib/python/qmk/cli/new/keymap.py
@@ -40,7 +40,7 @@ def new_keymap(cli):
40 exit(1) 40 exit(1)
41 41
42 # create user directory with default keymap files 42 # create user directory with default keymap files
43 shutil.copytree(str(keymap_path_default), str(keymap_path_new), symlinks=True) 43 shutil.copytree(keymap_path_default, keymap_path_new, symlinks=True)
44 44
45 # end message to user 45 # end message to user
46 cli.log.info("%s keymap directory created in: %s", keymap, keymap_path_new) 46 cli.log.info("%s keymap directory created in: %s", keymap, keymap_path_new)
diff --git a/lib/python/qmk/keymap.py b/lib/python/qmk/keymap.py
index 4aa87de20..69cdc8d5b 100644
--- a/lib/python/qmk/keymap.py
+++ b/lib/python/qmk/keymap.py
@@ -1,6 +1,5 @@
1"""Functions that help you work with QMK keymaps. 1"""Functions that help you work with QMK keymaps.
2""" 2"""
3import os
4from pathlib import Path 3from pathlib import Path
5 4
6import qmk.path 5import qmk.path
@@ -127,7 +126,7 @@ def list_keymaps(keyboard_name):
127 while kb_path != keyboards_dir: 126 while kb_path != keyboards_dir:
128 keymaps_dir = kb_path / "keymaps" 127 keymaps_dir = kb_path / "keymaps"
129 if keymaps_dir.exists(): 128 if keymaps_dir.exists():
130 names = names.union([keymap for keymap in os.listdir(str(keymaps_dir)) if (keymaps_dir / keymap / "keymap.c").is_file()]) 129 names = names.union([keymap for keymap in keymaps_dir.iterdir() if (keymaps_dir / keymap / "keymap.c").is_file()])
131 kb_path = kb_path.parent 130 kb_path = kb_path.parent
132 131
133 # if community layouts are supported, get them 132 # if community layouts are supported, get them
@@ -135,6 +134,6 @@ def list_keymaps(keyboard_name):
135 for layout in rules_mk["LAYOUTS"].split(): 134 for layout in rules_mk["LAYOUTS"].split():
136 cl_path = Path.cwd() / "layouts" / "community" / layout 135 cl_path = Path.cwd() / "layouts" / "community" / layout
137 if cl_path.exists(): 136 if cl_path.exists():
138 names = names.union([keymap for keymap in os.listdir(str(cl_path)) if (cl_path / keymap / "keymap.c").is_file()]) 137 names = names.union([keymap for keymap in cl_path.iterdir() if (cl_path / keymap / "keymap.c").is_file()])
139 138
140 return sorted(names) 139 return sorted(names)