diff --git a/dist/tools/compile_and_test_for_board/compile_and_test_for_board.py b/dist/tools/compile_and_test_for_board/compile_and_test_for_board.py index 5da1f94a2e..64b017d61d 100755 --- a/dist/tools/compile_and_test_for_board/compile_and_test_for_board.py +++ b/dist/tools/compile_and_test_for_board/compile_and_test_for_board.py @@ -1,5 +1,6 @@ #! /usr/bin/env python3 +# pylint: disable=line-too-long """ This script handles building all applications and tests for one board and also execute tests if they are available. @@ -103,9 +104,9 @@ except ImportError: LOG_HANDLER = logging.StreamHandler() LOG_HANDLER.setFormatter(logging.Formatter(logging.BASIC_FORMAT)) -LOG_LEVELS = ('debug', 'info', 'warning', 'error', 'fatal', 'critical') +LOG_LEVELS = ("debug", "info", "warning", "error", "fatal", "critical") -MAKE = os.environ.get('MAKE', 'make') +MAKE = os.environ.get("MAKE", "make") class ErrorInTest(Exception): @@ -114,6 +115,7 @@ class ErrorInTest(Exception): It contains the step that failed in 'message', the 'application' and the 'errorfile' path to the execution error. """ + def __init__(self, message, application, errorfile): super().__init__(message) self.application = application @@ -168,10 +170,10 @@ def apps_directories(riotdir, apps_dirs=None, apps_dirs_skip=None): def _riot_applications_dirs(riotdir): """Applications directories in the RIOT repository with relative path.""" - cmd = [MAKE, 'info-applications'] + cmd = [MAKE, "info-applications"] out = subprocess.check_output(cmd, cwd=riotdir) - out = out.decode('utf-8', errors='replace') + out = out.decode("utf-8", errors="replace") return out.split() @@ -181,9 +183,9 @@ def check_is_board(riotdir, board): :raises ValueError: on invalid board :returns: board name """ - if board == 'common': + if board == "common": raise ValueError(f"'{board}' is not a board") - board_dir = os.path.join(riotdir, 'boards', board) + board_dir = os.path.join(riotdir, "boards", board) if not os.path.isdir(board_dir): raise ValueError(f"Cannot find '{board}' in {riotdir}/boards") return board @@ -220,7 +222,7 @@ def is_in_directory(path, directory): return path.startswith(directory) -class RIOTApplication(): +class RIOTApplication: """RIOT Application representation. Allows calling make commands on an application for a board. @@ -232,12 +234,15 @@ class RIOTApplication(): :param junit: track application in JUnit XML """ - MAKEFLAGS = ('RIOT_CI_BUILD=1', 'CC_NOCOLOR=1', '--no-print-directory') + MAKEFLAGS = ("RIOT_CI_BUILD=1", "CC_NOCOLOR=1", "--no-print-directory") - COMPILE_TARGETS = ('clean', 'all',) - FLASH_TARGETS = ('flash-only',) - TEST_TARGETS = ('test',) - TEST_AVAILABLE_TARGETS = ('test/available',) + COMPILE_TARGETS = ( + "clean", + "all", + ) + FLASH_TARGETS = ("flash-only",) + TEST_TARGETS = ("test",) + TEST_AVAILABLE_TARGETS = ("test/available",) # pylint: disable=too-many-arguments def __init__(self, board, riotdir, appdir, resultdir, junit=False): @@ -248,24 +253,23 @@ class RIOTApplication(): if junit: if not junit_xml: raise ImportError("`junit-xml` required for --report-xml") - self.testcase = junit_xml.TestCase(name=self.appdir, - stdout='', stderr='') + self.testcase = junit_xml.TestCase(name=self.appdir, stdout="", stderr="") self.log_stream = io.StringIO() logging.basicConfig(stream=self.log_stream) else: self.testcase = None - self.logger = logging.getLogger(f'{board}.{appdir}') + self.logger = logging.getLogger(f"{board}.{appdir}") # Currently not handling absolute directories or outside of RIOT - assert is_in_directory(self.resultdir, resultdir), \ - "Application result directory is outside main result directory" + assert is_in_directory( + self.resultdir, resultdir + ), "Application result directory is outside main result directory" # Extract values from make def name(self): """Get application name.""" - appname = self.make(['info-debug-variable-APPLICATION'], - log_error=True).strip() - self.logger.debug('APPLICATION: %s', appname) + appname = self.make(["info-debug-variable-APPLICATION"], log_error=True).strip() + self.logger.debug("APPLICATION: %s", appname) return appname def has_test(self): @@ -279,48 +283,49 @@ class RIOTApplication(): has_test = False else: has_test = True - self.logger.info('Application has test: %s', has_test) + self.logger.info("Application has test: %s", has_test) return has_test def board_is_supported(self): """Return if current board is supported.""" - env = {'BOARDS': self.board} - cmd = ['info-boards-supported'] + env = {"BOARDS": self.board} + cmd = ["info-boards-supported"] ret = self.make(cmd, env=env, log_error=True).strip() supported = ret == self.board - self.logger.info('Board supported: %s', supported) + self.logger.info("Board supported: %s", supported) return supported def board_has_enough_memory(self): """Return if current board has enough memory.""" - cmd = ['info-debug-variable-BOARD_INSUFFICIENT_MEMORY'] + cmd = ["info-debug-variable-BOARD_INSUFFICIENT_MEMORY"] boards = self.make(cmd, log_error=True).strip().split() has_enough_memory = self.board not in boards - self.logger.info('Board has enough memory: %s', has_enough_memory) + self.logger.info("Board has enough memory: %s", has_enough_memory) return has_enough_memory def clean(self): """Clean build and packages.""" try: - cmd = ['clean', 'clean-pkg'] + cmd = ["clean", "clean-pkg"] self.make(cmd) except subprocess.CalledProcessError as err: if self.testcase: - self.testcase.stderr += err.output + '\n' - self.logger.warning('Got an error during clean, ignore: %r', err) + self.testcase.stderr += err.output + "\n" + self.logger.warning("Got an error during clean, ignore: %r", err) def clean_intermediates(self): """Clean intermediates only.""" try: - cmd = ['clean-intermediates'] + cmd = ["clean-intermediates"] self.make(cmd) except subprocess.CalledProcessError as err: if self.testcase: - self.testcase.stderr += err.output + '\n' - self.logger.warning('Got an error during clean-intermediates,' - ' ignore: %r', err) + self.testcase.stderr += err.output + "\n" + self.logger.warning( + "Got an error during clean-intermediates," " ignore: %r", err + ) def run_compilation_and_test(self, **test_kwargs): """Same as `compilation_and_test` but handles exception. @@ -333,7 +338,7 @@ class RIOTApplication(): self.compilation_and_test(**test_kwargs) res = None except ErrorInTest as err: - self.logger.error('Failed during: %s', err) + self.logger.error("Failed during: %s", err) res = (str(err), err.application.appdir, err.errorfile) if self.testcase: self.testcase.elapsed_sec = time.time() - self.testcase.timestamp @@ -350,11 +355,16 @@ class RIOTApplication(): skip_reason_details if skip_reason_details else skip_reason, output, ) - self._write_resultfile('skip', skip_reason) + self._write_resultfile("skip", skip_reason) - def compilation_and_test(self, clean_after=False, runtest=True, - incremental=False, jobs=False, - with_test_only=False): + def compilation_and_test( + self, + clean_after=False, + runtest=True, + incremental=False, + jobs=False, + with_test_only=False, + ): # pylint:disable=too-many-arguments """Compile and execute test if available. @@ -375,14 +385,14 @@ class RIOTApplication(): # Ignore incompatible APPS if not self.board_is_supported(): create_directory(self.resultdir, clean=True) - self._skip('not_supported', 'Board not supported') + self._skip("not_supported", "Board not supported") return if not self.board_has_enough_memory(): create_directory(self.resultdir, clean=True) self._skip( - 'not_enough_memory', - 'Board has not enough memory to carry application', + "not_enough_memory", + "Board has not enough memory to carry application", ) return @@ -390,10 +400,7 @@ class RIOTApplication(): if with_test_only and not has_test: create_directory(self.resultdir, clean=True) - self._skip( - 'disabled_has_no_tests', - f"{self.appdir} has no tests" - ) + self._skip("disabled_has_no_tests", f"{self.appdir} has no tests") return # Normal case for supported apps @@ -404,60 +411,55 @@ class RIOTApplication(): compilation_cmd = list(self.COMPILE_TARGETS) if jobs is not None: - compilation_cmd += ['--jobs'] + compilation_cmd += ["--jobs"] if jobs: compilation_cmd += [str(jobs)] - self.make_with_outfile('compilation', compilation_cmd) + self.make_with_outfile("compilation", compilation_cmd) if clean_after: self.clean_intermediates() if runtest: if has_test: - setuptasks = collections.OrderedDict( - [('flash', self.FLASH_TARGETS)]) - self.make_with_outfile('test', self.TEST_TARGETS, - save_output=True, setuptasks=setuptasks) + setuptasks = collections.OrderedDict([("flash", self.FLASH_TARGETS)]) + self.make_with_outfile( + "test", self.TEST_TARGETS, save_output=True, setuptasks=setuptasks + ) if clean_after: self.clean() else: - self._skip( - 'skip.no_test', - f"{self.appdir} has no tests" - ) + self._skip("skip.no_test", f"{self.appdir} has no tests") - self.logger.info('Success') + self.logger.info("Success") def make(self, args, env=None, log_error=False): """Run make command in appdir.""" env = env or {} # HACK: BOARD should be set for make in environment and not command # line either it break the `BOARD=none` for global commands - env['BOARD'] = self.board + env["BOARD"] = self.board full_env = os.environ.copy() full_env.update(env) cmd = [MAKE] cmd.extend(self.MAKEFLAGS) - cmd.extend(['-C', os.path.join(self.riotdir, self.appdir)]) + cmd.extend(["-C", os.path.join(self.riotdir, self.appdir)]) cmd.extend(args) - self.logger.debug('%r ENV %s', cmd, env) + self.logger.debug("%r ENV %s", cmd, env) # Call without 'universal_newlines' to have bytes and handle decoding # (encoding and errors are only supported after python 3.6) try: - out = subprocess.check_output(cmd, env=full_env, - stderr=subprocess.STDOUT) - out = out.decode('utf-8', errors='replace') + out = subprocess.check_output(cmd, env=full_env, stderr=subprocess.STDOUT) + out = out.decode("utf-8", errors="replace") except subprocess.CalledProcessError as err: - err.output = err.output.decode('utf-8', errors='replace') + err.output = err.output.decode("utf-8", errors="replace") if log_error: - self.logger.error('Error during command: \n%s', err.output) + self.logger.error("Error during command: \n%s", err.output) raise err return out - def make_with_outfile(self, name, args, save_output=False, - setuptasks=None): + def make_with_outfile(self, name, args, save_output=False, setuptasks=None): """Run make but save result in an outfile. It will be saved in `self.resultdir/name.[success|failure]`. @@ -467,20 +469,20 @@ class RIOTApplication(): if not, return an empty string. :param setuptasks: OrderedDict of tasks to run before the main one """ - self.logger.info('Run %s', name) + self.logger.info("Run %s", name) setuptasks = setuptasks or {} # Do not re-run if success output = self._make_get_previous_output(name) if output is not None: if self.testcase: - self.testcase.stdout += output + '\n' + self.testcase.stdout += output + "\n" return # Run setup-tasks, output is only kept in case of error for taskname, taskargs in setuptasks.items(): - taskname = f'{name}.{taskname}' - self.logger.info('Run %s', taskname) + taskname = f"{name}.{taskname}" + self.logger.info("Run %s", taskname) try: self.make(taskargs) except subprocess.CalledProcessError as err: @@ -490,10 +492,10 @@ class RIOTApplication(): try: output = self.make(args) if not save_output: - output = '' + output = "" if self.testcase: - self.testcase.stdout += output + '\n' - self._write_resultfile(name, 'success', output) + self.testcase.stdout += output + "\n" + self._write_resultfile(name, "success", output) except subprocess.CalledProcessError as err: self._make_handle_error(name, err) @@ -503,9 +505,8 @@ class RIOTApplication(): Returns `output` if it is there, None if not. """ try: - with open(self._outfile(f'{name}.success'), - encoding='utf-8') as outputfd: - self.logger.info('Nothing to be done for %s', name) + with open(self._outfile(f"{name}.success"), encoding="utf-8") as outputfd: + self.logger.info("Nothing to be done for %s", name) return outputfd.read() except OSError: pass @@ -513,31 +514,29 @@ class RIOTApplication(): def _make_handle_error(self, name, err): """Handle exception during make step `name`.""" - output = ' '.join(err.cmd) + '\n' - output += err.output + '\n' - output += f'Return value: {err.returncode}\n' - outfile = self._write_resultfile(name, 'failed', output) + output = " ".join(err.cmd) + "\n" + output += err.output + "\n" + output += f"Return value: {err.returncode}\n" + outfile = self._write_resultfile(name, "failed", output) self.logger.warning(output) - self.logger.error('Error during %s, writing to %s', name, outfile) + self.logger.error("Error during %s, writing to %s", name, outfile) if self.testcase: - self.testcase.stderr += err.output + '\n' + self.testcase.stderr += err.output + "\n" if name == "test": - self.testcase.add_failure_info(f"{err.cmd} failed", - err.output) + self.testcase.add_failure_info(f"{err.cmd} failed", err.output) else: - self.testcase.add_error_info(f"{err.cmd} had an error", - err.output) + self.testcase.add_error_info(f"{err.cmd} had an error", err.output) raise ErrorInTest(name, self, outfile) - def _write_resultfile(self, name, status, body=''): + def _write_resultfile(self, name, status, body=""): """Write `body` to result file `name.status`. It also deletes other `name.*` files before. """ # Delete previous status files - resultfiles = glob.glob(self._outfile(f'{name}.*')) + resultfiles = glob.glob(self._outfile(f"{name}.*")) for resultfile in resultfiles: try: os.remove(resultfile) @@ -545,11 +544,10 @@ class RIOTApplication(): pass # Create new file - filename = f'{name}.{status}' + filename = f"{name}.{status}" outfile = self._outfile(filename) - with open(outfile, 'w+', encoding='utf-8', - errors='replace') as outfd: + with open(outfile, "w+", encoding="utf-8", errors="replace") as outfd: outfd.write(body) outfd.flush() return outfile @@ -559,7 +557,7 @@ class RIOTApplication(): return os.path.join(self.resultdir, filename) -TOOLCHAIN_SCRIPT = 'dist/tools/ci/print_toolchain_versions.sh' +TOOLCHAIN_SCRIPT = "dist/tools/ci/print_toolchain_versions.sh" def print_toolchain(riotdir): @@ -569,23 +567,23 @@ def print_toolchain(riotdir): """ toolchain_script = os.path.join(riotdir, TOOLCHAIN_SCRIPT) out = subprocess.check_output([toolchain_script]) - return out.decode('utf-8', errors='replace') + return out.decode("utf-8", errors="replace") def save_toolchain(riotdir, resultdir): """Save toolchain in 'resultdir/toolchain'.""" - outfile = os.path.join(resultdir, 'toolchain') + outfile = os.path.join(resultdir, "toolchain") create_directory(resultdir) toolchain = print_toolchain(riotdir) - with open(outfile, 'w+', encoding='utf-8', errors='replace') as outputfd: + with open(outfile, "w+", encoding="utf-8", errors="replace") as outputfd: outputfd.write(toolchain) def _test_failed_summary(errors, relpathstart=None): """Generate a test summary for failures.""" if not errors: - return '' + return "" errors_dict = {} for step, appdir, errorfile in errors: @@ -593,13 +591,13 @@ def _test_failed_summary(errors, relpathstart=None): errorfile = os.path.relpath(errorfile, relpathstart) errors_dict.setdefault(step, []).append((appdir, errorfile)) - summary = '' + summary = "" for step, errs in sorted(errors_dict.items()): - summary += f'Failures during {step}:\n' + summary += f"Failures during {step}:\n" for appdir, errorfile in errs: - summary += f'- [{appdir}]({errorfile})\n' + summary += f"- [{appdir}]({errorfile})\n" # Separate sections with a new line - summary += '\n' + summary += "\n" # Remove last new line summary = summary[:-1] @@ -608,9 +606,9 @@ def _test_failed_summary(errors, relpathstart=None): def save_failure_summary(resultdir, summary): """Save test summary in 'resultdir/board/failuresummary'.""" - outfile = os.path.join(resultdir, 'failuresummary.md') + outfile = os.path.join(resultdir, "failuresummary.md") - with open(outfile, 'w+', encoding='utf-8', errors='replace') as outputfd: + with open(outfile, "w+", encoding="utf-8", errors="replace") as outputfd: outputfd.write(summary) @@ -633,7 +631,7 @@ def list_from_string(list_str=None): >>> list_from_string("a b c") ['a', 'b', 'c'] """ - value = (list_str or '').split(' ') + value = (list_str or "").split(" ") return [v for v in value if v] @@ -642,57 +640,96 @@ def _strip_board_equal(board): Increase RIOT compatibility. """ - if board.startswith('BOARD='): - board = board.replace('BOARD=', '') + if board.startswith("BOARD="): + board = board.replace("BOARD=", "") return board -PARSER = argparse.ArgumentParser( - formatter_class=argparse.ArgumentDefaultsHelpFormatter) -PARSER.add_argument('riot_directory', help='RIOT directory to test') -PARSER.add_argument('board', help='Board to test', type=_strip_board_equal) -PARSER.add_argument('result_directory', nargs='?', default='results', - help='Result directory') +PARSER = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter) +PARSER.add_argument("riot_directory", help="RIOT directory to test") +PARSER.add_argument("board", help="Board to test", type=_strip_board_equal) PARSER.add_argument( - '--applications', type=list_from_string, - help=('List of applications to test, overwrites default configuration of' - ' testing all applications'), + "result_directory", nargs="?", default="results", help="Result directory" ) PARSER.add_argument( - '--applications-exclude', type=list_from_string, - help=('List of applications to exclude from tested applications.' - ' Also applied after "--applications".'), + "--applications", + type=list_from_string, + help=( + "List of applications to test, overwrites default configuration of" + " testing all applications" + ), +) +PARSER.add_argument( + "--applications-exclude", + type=list_from_string, + help=( + "List of applications to exclude from tested applications." + ' Also applied after "--applications".' + ), +) +PARSER.add_argument( + "--no-test", action="store_true", default=False, help="Disable executing tests" +) +PARSER.add_argument( + "--with-test-only", + action="store_true", + default=False, + help="Only compile applications that have a test", +) +PARSER.add_argument( + "--loglevel", choices=LOG_LEVELS, default="info", help="Python logger log level" +) +PARSER.add_argument( + "--incremental", + action="store_true", + default=False, + help="Do not rerun successful compilation and tests", +) +PARSER.add_argument( + "--clean-after", + action="store_true", + default=False, + help="Clean after running each test", ) -PARSER.add_argument('--no-test', action='store_true', default=False, - help='Disable executing tests') -PARSER.add_argument('--with-test-only', action='store_true', default=False, - help='Only compile applications that have a test') -PARSER.add_argument('--loglevel', choices=LOG_LEVELS, default='info', - help='Python logger log level') -PARSER.add_argument('--incremental', action='store_true', default=False, - help='Do not rerun successful compilation and tests') -PARSER.add_argument('--clean-after', action='store_true', default=False, - help='Clean after running each test') - -PARSER.add_argument('--compile-targets', type=list_from_string, - default=' '.join(RIOTApplication.COMPILE_TARGETS), - help='List of make targets to compile') -PARSER.add_argument('--flash-targets', type=list_from_string, - default=' '.join(RIOTApplication.FLASH_TARGETS), - help='List of make targets to flash') -PARSER.add_argument('--test-targets', type=list_from_string, - default=' '.join(RIOTApplication.TEST_TARGETS), - help='List of make targets to run test') -PARSER.add_argument('--test-available-targets', type=list_from_string, - default=' '.join(RIOTApplication.TEST_AVAILABLE_TARGETS), - help='List of make targets to know if a test is present') -PARSER.add_argument('--report-xml', action='store_true', default=False, - help='Output results to report.xml in the ' - 'result_directory') PARSER.add_argument( - '--jobs', '-j', type=int, default=None, - help="Parallel building (0 means not limit, like '--jobs')") + "--compile-targets", + type=list_from_string, + default=" ".join(RIOTApplication.COMPILE_TARGETS), + help="List of make targets to compile", +) +PARSER.add_argument( + "--flash-targets", + type=list_from_string, + default=" ".join(RIOTApplication.FLASH_TARGETS), + help="List of make targets to flash", +) +PARSER.add_argument( + "--test-targets", + type=list_from_string, + default=" ".join(RIOTApplication.TEST_TARGETS), + help="List of make targets to run test", +) +PARSER.add_argument( + "--test-available-targets", + type=list_from_string, + default=" ".join(RIOTApplication.TEST_AVAILABLE_TARGETS), + help="List of make targets to know if a test is present", +) +PARSER.add_argument( + "--report-xml", + action="store_true", + default=False, + help="Output results to report.xml in the " "result_directory", +) + +PARSER.add_argument( + "--jobs", + "-j", + type=int, + default=None, + help="Parallel building (0 means not limit, like '--jobs')", +) def main(args): @@ -704,23 +741,24 @@ def main(args): logger.addHandler(LOG_HANDLER) - logger.info('Saving toolchain') + logger.info("Saving toolchain") save_toolchain(args.riot_directory, args.result_directory) board = check_is_board(args.riot_directory, args.board) - logger.debug('board: %s', board) + logger.debug("board: %s", board) # Expand application directories: allows use of glob in application names - apps_dirs = _expand_apps_directories(args.applications, - args.riot_directory) - apps_dirs_skip = _expand_apps_directories(args.applications_exclude, - args.riot_directory, skip=True) + apps_dirs = _expand_apps_directories(args.applications, args.riot_directory) + apps_dirs_skip = _expand_apps_directories( + args.applications_exclude, args.riot_directory, skip=True + ) - app_dirs = apps_directories(args.riot_directory, apps_dirs=apps_dirs, - apps_dirs_skip=apps_dirs_skip) + app_dirs = apps_directories( + args.riot_directory, apps_dirs=apps_dirs, apps_dirs_skip=apps_dirs_skip + ) - logger.debug('app_dirs: %s', app_dirs) - logger.debug('resultdir: %s', args.result_directory) + logger.debug("app_dirs: %s", app_dirs) + logger.debug("resultdir: %s", args.result_directory) board_result_directory = os.path.join(args.result_directory, args.board) # Overwrite the compile/test targets from command line arguments @@ -730,18 +768,28 @@ def main(args): RIOTApplication.TEST_AVAILABLE_TARGETS = args.test_available_targets # List of applications for board - applications = [RIOTApplication(board, args.riot_directory, app_dir, - board_result_directory, - junit=args.report_xml) - for app_dir in app_dirs] + applications = [ + RIOTApplication( + board, + args.riot_directory, + app_dir, + board_result_directory, + junit=args.report_xml, + ) + for app_dir in app_dirs + ] # Execute tests - errors = [app.run_compilation_and_test(clean_after=args.clean_after, - runtest=not args.no_test, - incremental=args.incremental, - jobs=args.jobs, - with_test_only=args.with_test_only) - for app in applications] + errors = [ + app.run_compilation_and_test( + clean_after=args.clean_after, + runtest=not args.no_test, + incremental=args.incremental, + jobs=args.jobs, + with_test_only=args.with_test_only, + ) + for app in applications + ] errors = [e for e in errors if e is not None] num_errors = len(errors) @@ -755,16 +803,20 @@ def main(args): with open(report_file, "w+", encoding="utf-8") as report: junit_xml.TestSuite.to_file( report, - [junit_xml.TestSuite(f'compile_and_test_for_{board}', - [app.testcase for app in applications])] + [ + junit_xml.TestSuite( + f"compile_and_test_for_{board}", + [app.testcase for app in applications], + ) + ], ) if num_errors: - logger.error('Tests failed: %d', num_errors) - print(summary, end='') + logger.error("Tests failed: %d", num_errors) + print(summary, end="") else: - logger.info('Tests successful') + logger.info("Tests successful") sys.exit(num_errors) -if __name__ == '__main__': +if __name__ == "__main__": main(PARSER.parse_args()) diff --git a/dist/tools/compile_and_test_for_board/setup.cfg b/dist/tools/compile_and_test_for_board/setup.cfg new file mode 100644 index 0000000000..37171e2678 --- /dev/null +++ b/dist/tools/compile_and_test_for_board/setup.cfg @@ -0,0 +1,12 @@ +# Use black compatible configuration for flake8 and pylint +# flake8: https://black.readthedocs.io/en/stable/guides/using_black_with_other_tools.html#flake8 +# pylint: https://black.readthedocs.io/en/stable/guides/using_black_with_other_tools.html#pylint +[flake8] +max-line-length = 88 +extend-ignore = E203 + +[pylint] +max-line-length = 88 + +[pylint.messages_control] +disable = C0330, C0326 diff --git a/dist/tools/compile_and_test_for_board/tox.ini b/dist/tools/compile_and_test_for_board/tox.ini index e55c7252e5..dcc6cf7867 100644 --- a/dist/tools/compile_and_test_for_board/tox.ini +++ b/dist/tools/compile_and_test_for_board/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = test,lint,flake8 +envlist = test,lint,flake8,black skipsdist = True [testenv] @@ -10,6 +10,7 @@ commands = test: {[testenv:test]commands} lint: {[testenv:lint]commands} flake8: {[testenv:flake8]commands} + black: {[testenv:black]commands} [testenv:test] deps = pytest @@ -19,9 +20,14 @@ commands = [testenv:lint] deps = pylint commands = - pylint {env:script} tests + pylint --rcfile=setup.cfg {env:script} tests [testenv:flake8] deps = flake8 commands = flake8 {env:script} tests + +[testenv:black] +deps = black +commands = + black --check --diff {env:script} tests