Move the module checking and updating to lib/python (#12416)

* move the module checking and updating to lib/python

* make flake8 happy

* Update lib/python/qmk/cli/__init__.py

Co-authored-by: Erovia <Erovia@users.noreply.github.com>

* prompt the user to disable developer mode

* pyformat

* flake8

Co-authored-by: Erovia <Erovia@users.noreply.github.com>
This commit is contained in:
Zach White 2021-05-10 12:00:52 -07:00 committed by GitHub
parent a3e7f3e7c5
commit bc38c38f8c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 121 additions and 68 deletions

44
bin/qmk
View File

@ -3,7 +3,6 @@
""" """
import os import os
import sys import sys
from importlib.util import find_spec
from pathlib import Path from pathlib import Path
# Add the QMK python libs to our path # Add the QMK python libs to our path
@ -12,52 +11,9 @@ qmk_dir = script_dir.parent
python_lib_dir = Path(qmk_dir / 'lib' / 'python').resolve() python_lib_dir = Path(qmk_dir / 'lib' / 'python').resolve()
sys.path.append(str(python_lib_dir)) sys.path.append(str(python_lib_dir))
def _check_modules(requirements):
""" Check if the modules in the given requirements.txt are available.
"""
with Path(qmk_dir / requirements).open() as fd:
for line in fd.readlines():
line = line.strip().replace('<', '=').replace('>', '=')
if len(line) == 0 or line[0] == '#' or line.startswith('-r'):
continue
if '#' in line:
line = line.split('#')[0]
module = dict()
module['name'] = line.split('=')[0] if '=' in line else line
module['import'] = module['name'].replace('-', '_')
# Not every module is importable by its own name.
if module['name'] == "pep8-naming":
module['import'] = "pep8ext_naming"
if not find_spec(module['import']):
print('Could not find module %s!' % module['name'])
print('Please run `python3 -m pip install -r %s` to install required python dependencies.' % (qmk_dir / requirements,))
if developer:
print('You can also turn off developer mode: qmk config user.developer=None')
print()
exit(255)
developer = False
# Make sure our modules have been setup
_check_modules('requirements.txt')
# Setup the CLI # Setup the CLI
import milc # noqa import milc # noqa
# For developers additional modules are needed
if milc.cli.config.user.developer:
# Do not run the check for 'config',
# so users can turn off developer mode
if len(sys.argv) == 1 or (len(sys.argv) > 1 and 'config' != sys.argv[1]):
developer = True
_check_modules('requirements-dev.txt')
milc.EMOJI_LOGLEVELS['INFO'] = '{fg_blue}Ψ{style_reset_all}' milc.EMOJI_LOGLEVELS['INFO'] = '{fg_blue}Ψ{style_reset_all}'

View File

@ -2,33 +2,79 @@
We list each subcommand here explicitly because all the reliable ways of searching for modules are slow and delay startup. We list each subcommand here explicitly because all the reliable ways of searching for modules are slow and delay startup.
""" """
import os
import shlex
import sys import sys
from importlib.util import find_spec
from pathlib import Path
from subprocess import run
from milc import cli, __VERSION__ from milc import cli, __VERSION__
from milc.questions import yesno
from . import c2json
from . import cformat
from . import chibios
from . import clean
from . import compile
from . import config
from . import docs
from . import doctor
from . import fileformat
from . import flash
from . import format
from . import generate
from . import hello
from . import info
from . import json2c
from . import lint
from . import list
from . import kle2json
from . import multibuild
from . import new
from . import pyformat
from . import pytest
def _run_cmd(*command):
"""Run a command in a subshell.
"""
if 'windows' in cli.platform.lower():
safecmd = map(shlex.quote, command)
safecmd = ' '.join(safecmd)
command = [os.environ['SHELL'], '-c', safecmd]
return run(command)
def _find_broken_requirements(requirements):
""" Check if the modules in the given requirements.txt are available.
Args:
requirements
The path to a requirements.txt file
Returns a list of modules that couldn't be imported
"""
with Path(requirements).open() as fd:
broken_modules = []
for line in fd.readlines():
line = line.strip().replace('<', '=').replace('>', '=')
if len(line) == 0 or line[0] == '#' or line.startswith('-r'):
continue
if '#' in line:
line = line.split('#')[0]
module_name = line.split('=')[0] if '=' in line else line
module_import = module_name.replace('-', '_')
# Not every module is importable by its own name.
if module_name == "pep8-naming":
module_import = "pep8ext_naming"
if not find_spec(module_import):
broken_modules.append(module_name)
return broken_modules
def _broken_module_imports(requirements):
"""Make sure we can import all the python modules.
"""
broken_modules = _find_broken_requirements(requirements)
for module in broken_modules:
print('Could not find module %s!' % module)
if broken_modules:
return True
return False
# Make sure our python is new enough
#
# Supported version information # Supported version information
# #
# Based on the OSes we support these are the minimum python version available by default. # Based on the OSes we support these are the minimum python version available by default.
@ -54,9 +100,60 @@ if sys.version_info[0] != 3 or sys.version_info[1] < 7:
milc_version = __VERSION__.split('.') milc_version = __VERSION__.split('.')
if int(milc_version[0]) < 2 and int(milc_version[1]) < 3: if int(milc_version[0]) < 2 and int(milc_version[1]) < 3:
from pathlib import Path
requirements = Path('requirements.txt').resolve() requirements = Path('requirements.txt').resolve()
print(f'Your MILC library is too old! Please upgrade: python3 -m pip install -U -r {str(requirements)}') print(f'Your MILC library is too old! Please upgrade: python3 -m pip install -U -r {str(requirements)}')
exit(127) exit(127)
# Check to make sure we have all our dependencies
msg_install = 'Please run `python3 -m pip install -r %s` to install required python dependencies.'
if _broken_module_imports('requirements.txt'):
if yesno('Would you like to install the required Python modules?'):
_run_cmd(sys.executable, '-m', 'pip', 'install', '-r', 'requirements.txt')
else:
print()
print(msg_install % (str(Path('requirements.txt').resolve()),))
print()
exit(1)
if cli.config.user.developer:
args = sys.argv[1:]
while args and args[0][0] == '-':
del args[0]
if not args or args[0] != 'config':
if _broken_module_imports('requirements-dev.txt'):
if yesno('Would you like to install the required developer Python modules?'):
_run_cmd(sys.executable, '-m', 'pip', 'install', '-r', 'requirements-dev.txt')
elif yesno('Would you like to disable developer mode?'):
_run_cmd(sys.argv[0], 'config', 'user.developer=None')
else:
print()
print(msg_install % (str(Path('requirements-dev.txt').resolve()),))
print('You can also turn off developer mode: qmk config user.developer=None')
print()
exit(1)
# Import our subcommands
from . import c2json # noqa
from . import cformat # noqa
from . import chibios # noqa
from . import clean # noqa
from . import compile # noqa
from . import config # noqa
from . import docs # noqa
from . import doctor # noqa
from . import fileformat # noqa
from . import flash # noqa
from . import format # noqa
from . import generate # noqa
from . import hello # noqa
from . import info # noqa
from . import json2c # noqa
from . import lint # noqa
from . import list # noqa
from . import kle2json # noqa
from . import multibuild # noqa
from . import new # noqa
from . import pyformat # noqa
from . import pytest # noqa