From 8f4c52a358358a671cccc720f39ef7e35cfc4d71 Mon Sep 17 00:00:00 2001 From: Marek Fiala Date: Thu, 4 Sep 2025 14:43:43 +0200 Subject: [PATCH] change(tools): ruff formatting core_ext.py --- tools/idf_py_actions/core_ext.py | 242 ++++++++++++++++++------------- 1 file changed, 144 insertions(+), 98 deletions(-) diff --git a/tools/idf_py_actions/core_ext.py b/tools/idf_py_actions/core_ext.py index 93d34461a5..5eb66402fe 100644 --- a/tools/idf_py_actions/core_ext.py +++ b/tools/idf_py_actions/core_ext.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: Apache-2.0 import fnmatch import glob @@ -10,9 +10,6 @@ import shutil import subprocess import sys from typing import Any -from typing import Dict -from typing import List -from typing import Optional from urllib.error import URLError from urllib.request import Request from urllib.request import urlopen @@ -20,25 +17,26 @@ from webbrowser import open_new_tab import click from click.core import Context + from idf_py_actions.constants import GENERATORS from idf_py_actions.constants import PREVIEW_TARGETS from idf_py_actions.constants import SUPPORTED_TARGETS from idf_py_actions.constants import URL_TO_DOC from idf_py_actions.errors import FatalError from idf_py_actions.global_options import global_options +from idf_py_actions.tools import PropertyDict +from idf_py_actions.tools import TargetChoice from idf_py_actions.tools import ensure_build_directory from idf_py_actions.tools import generate_hints from idf_py_actions.tools import get_target from idf_py_actions.tools import idf_version from idf_py_actions.tools import merge_action_lists from idf_py_actions.tools import print_warning -from idf_py_actions.tools import PropertyDict from idf_py_actions.tools import run_target -from idf_py_actions.tools import TargetChoice from idf_py_actions.tools import yellow_print -def action_extensions(base_actions: Dict, project_path: str) -> Any: +def action_extensions(base_actions: dict, project_path: str) -> Any: def build_target(target_name: str, ctx: Context, args: PropertyDict) -> None: """ Execute the target build system to build target 'target_name' @@ -49,8 +47,15 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any: ensure_build_directory(args, ctx.info_name) run_target(target_name, args, force_progression=GENERATORS[args.generator].get('force_progression', False)) - def size_target(target_name: str, ctx: Context, args: PropertyDict, output_format: str, - output_file: str, diff_map_file: str, legacy: bool) -> None: + def size_target( + target_name: str, + ctx: Context, + args: PropertyDict, + output_format: str, + output_file: str, + diff_map_file: str, + legacy: bool, + ) -> None: """ Builds the app and then executes a size-related target passed in 'target_name'. `tool_error_handler` handler is used to suppress errors during the build, @@ -61,7 +66,7 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any: for hint in generate_hints(stdout, stderr): yellow_print(hint) - env: Dict[str, Any] = {} + env: dict[str, Any] = {} if not legacy and output_format != 'json': try: @@ -93,7 +98,9 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any: # The diff_map_file argument is a directory. Try to look for the map # file directly in it, in case it's a build directory or in one level below # if it's a project directory. - files = glob.glob(os.path.join(diff_map_file, '*.map')) or glob.glob(os.path.join(diff_map_file, '*/*.map')) + files = glob.glob(os.path.join(diff_map_file, '*.map')) or glob.glob( + os.path.join(diff_map_file, '*/*.map') + ) if not files: raise FatalError(f'No diff map file found in {diff_map_file} directory') if len(files) > 1: @@ -104,8 +111,12 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any: env['SIZE_DIFF_FILE'] = diff_map_file ensure_build_directory(args, ctx.info_name) - run_target('all', args, force_progression=GENERATORS[args.generator].get('force_progression', False), - custom_error_handler=tool_error_handler) + run_target( + 'all', + args, + force_progression=GENERATORS[args.generator].get('force_progression', False), + custom_error_handler=tool_error_handler, + ) run_target(target_name, args, env=env) def list_build_system_targets(target_name: str, ctx: Context, args: PropertyDict) -> None: @@ -121,13 +132,15 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any: try: import curses # noqa: F401 except ImportError: - raise FatalError('\n'.join( - ['', "menuconfig failed to import the standard Python 'curses' library.", - 'Please re-run the install script which might be able to fix the issue.'])) - if sys.version_info[0] < 3: - # The subprocess lib cannot accept environment variables as "unicode". - # This encoding step is required only in Python 2. - style = style.encode(sys.getfilesystemencoding() or 'utf-8') + raise FatalError( + '\n'.join( + [ + '', + "menuconfig failed to import the standard Python 'curses' library.", + 'Please re-run the install script which might be able to fix the issue.', + ] + ) + ) os.environ['MENUCONFIG_STYLE'] = style args.no_hints = True build_target(target_name, ctx, args) @@ -151,15 +164,16 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any: except Exception: if target_name in ['clang-check', 'clang-html-report']: - raise FatalError('command "{}" requires an additional plugin "pyclang". ' - 'Please install it via "pip install --upgrade pyclang"'.format(target_name)) + raise FatalError( + f'command "{target_name}" requires an additional plugin "pyclang". ' + 'Please install it via "pip install --upgrade pyclang"' + ) - raise FatalError( - 'command "%s" is not known to idf.py and is not a %s target' % (target_name, args.generator)) + raise FatalError(f'command "{target_name}" is not known to idf.py and is not a {args.generator} target') run_target(target_name, args) - def verbose_callback(ctx: Context, param: List, value: str) -> Optional[str]: + def verbose_callback(ctx: Context, param: list, value: str) -> str | None: if not value or ctx.resilient_parsing: return None @@ -170,36 +184,39 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any: def clean(action: str, ctx: Context, args: PropertyDict) -> None: if not os.path.isdir(args.build_dir): - print("Build directory '%s' not found. Nothing to clean." % args.build_dir) + print(f"Build directory '{args.build_dir}' not found. Nothing to clean.") return build_target('clean', ctx, args) def fullclean(action: str, ctx: Context, args: PropertyDict) -> None: build_dir = args.build_dir if not os.path.isdir(build_dir): - print("Build directory '%s' not found. Nothing to clean." % build_dir) + print(f"Build directory '{build_dir}' not found. Nothing to clean.") return if len(os.listdir(build_dir)) == 0: - print("Build directory '%s' is empty. Nothing to clean." % build_dir) + print(f"Build directory '{build_dir}' is empty. Nothing to clean.") return if not os.path.exists(os.path.join(build_dir, 'CMakeCache.txt')): raise FatalError( - "Directory '%s' doesn't seem to be a CMake build directory. Refusing to automatically " - "delete files in this directory. Delete the directory manually to 'clean' it." % build_dir) + f"Directory '{build_dir}' doesn't seem to be a CMake build directory. Refusing to automatically " + "delete files in this directory. Delete the directory manually to 'clean' it." + ) red_flags = ['CMakeLists.txt', '.git', '.svn'] for red in red_flags: red = os.path.join(build_dir, red) if os.path.exists(red): raise FatalError( - "Refusing to automatically delete files in directory containing '%s'. Delete files manually if you're sure." - % red) + f"Refusing to automatically delete files in directory containing '{red}'. " + "Delete files manually if you're sure." + ) if args.verbose and len(build_dir) > 1: - print('The following symlinks were identified and removed:\n%s' % '\n'.join(build_dir)) + symlinks_list = '\n'.join(build_dir) + print(f'The following symlinks were identified and removed:\n{symlinks_list}') for f in os.listdir(build_dir): # TODO: once we are Python 3 only, this can be os.scandir() f = os.path.join(build_dir, f) if args.verbose: - print('Removing: %s' % f) + print(f'Removing: {f}') if os.path.isdir(f): shutil.rmtree(f) else: @@ -211,19 +228,20 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any: if d == '__pycache__': dir_to_delete = os.path.join(root, d) if args.verbose: - print('Removing: %s' % dir_to_delete) + print(f'Removing: {dir_to_delete}') shutil.rmtree(dir_to_delete) for filename in fnmatch.filter(filenames, '*.py[co]'): file_to_delete = os.path.join(root, filename) if args.verbose: - print('Removing: %s' % file_to_delete) + print(f'Removing: {file_to_delete}') os.remove(file_to_delete) def set_target(action: str, ctx: Context, args: PropertyDict, idf_target: str) -> None: - if (not args['preview'] and idf_target in PREVIEW_TARGETS): + if not args['preview'] and idf_target in PREVIEW_TARGETS: raise FatalError( - "%s is still in preview. You have to append '--preview' option after idf.py to use any preview feature." - % idf_target) + f"{idf_target} is still in preview. You have to append '--preview' option after " + 'idf.py to use any preview feature.' + ) args.define_cache_entry.append('IDF_TARGET=' + idf_target) print(f'Set Target to: {idf_target}, new sdkconfig will be created.') env = {'_IDF_PY_SET_TARGET_ACTION': '1'} @@ -232,12 +250,13 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any: def reconfigure(action: str, ctx: Context, args: PropertyDict) -> None: ensure_build_directory(args, ctx.info_name, True) - def validate_root_options(ctx: Context, args: PropertyDict, tasks: List) -> None: + def validate_root_options(ctx: Context, args: PropertyDict, tasks: list) -> None: args.project_dir = os.path.realpath(args.project_dir) if args.build_dir is not None and args.project_dir == os.path.realpath(args.build_dir): raise FatalError( 'Setting the build directory to the project directory is not supported. Suggest dropping ' - "--build-dir option, the default is a 'build' subdirectory inside the project directory.") + "--build-dir option, the default is a 'build' subdirectory inside the project directory." + ) if args.build_dir is None: args.build_dir = os.path.join(args.project_dir, 'build') args.build_dir = os.path.realpath(args.build_dir) @@ -251,10 +270,10 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any: if not version: raise FatalError('ESP-IDF version cannot be determined') - print('ESP-IDF %s' % version) + print(f'ESP-IDF {version}') sys.exit(0) - def list_targets_callback(ctx: Context, param: List, value: int) -> None: + def list_targets_callback(ctx: Context, param: list, value: int) -> None: if not value or ctx.resilient_parsing: return @@ -267,7 +286,16 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any: sys.exit(0) - def show_docs(action: str, ctx: Context, args: PropertyDict, no_browser: bool, language: str, starting_page: str, version: str, target: str) -> None: + def show_docs( + action: str, + ctx: Context, + args: PropertyDict, + no_browser: bool, + language: str, + starting_page: str, + version: str, + target: str, + ) -> None: if language == 'cn': language = 'zh_CN' if not version: @@ -288,7 +316,7 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any: except URLError: print("We can't check the link's functionality because you don't have an internet connection") if redirect_link: - print('Target', target, 'doesn\'t exist for version', version) + print('Target', target, "doesn't exist for version", version) link = '/'.join([URL_TO_DOC, language, version, starting_page or '']) if not no_browser: print('Opening documentation in the default browser:') @@ -306,7 +334,7 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any: language = 'en' return language - def help_and_exit(action: str, ctx: Context, param: List, json_option: bool, add_options: bool) -> None: + def help_and_exit(action: str, ctx: Context, param: list, json_option: bool, add_options: bool) -> None: if json_option: output_dict = {} output_dict['target'] = get_target(param.project_dir) # type: ignore @@ -355,8 +383,10 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any: }, { 'names': ['-w/-n', '--cmake-warn-uninitialized/--no-warnings'], - 'help': ('Enable CMake uninitialized variable warnings for CMake files inside the project directory. ' - "(--no-warnings is now the default, and doesn't need to be specified.)"), + 'help': ( + 'Enable CMake uninitialized variable warnings for CMake files inside the project directory. ' + "(--no-warnings is now the default, and doesn't need to be specified.)" + ), 'envvar': 'IDF_CMAKE_WARN_UNINITIALIZED', 'is_flag': True, 'default': False, @@ -399,8 +429,8 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any: 'names': ['--no-hints'], 'help': 'Disable hints on how to resolve errors and logging.', 'is_flag': True, - 'default': False - } + 'default': False, + }, ], 'global_action_callbacks': [validate_root_options], } @@ -408,19 +438,31 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any: # 'default' is introduced instead of simply setting 'text' as the default so that we know # if the user explicitly specified the format or not. If the format is not specified, then # the legacy OUTPUT_JSON CMake variable will be taken into account. - size_options = [{'names': ['--format', 'output_format'], - 'type': click.Choice(['default', 'text', 'csv', 'json', 'json2', 'tree', 'raw']), - 'help': 'Specify output format: text (same as "default"), csv, json, json2, tree or raw.', - 'default': 'default'}, - {'names': ['--legacy', '-l'], - 'is_flag': True, - 'default': os.environ.get('ESP_IDF_SIZE_LEGACY', '0') == '1', - 'help': 'Use legacy esp-idf-size version'}, - {'names': ['--diff', 'diff_map_file'], - 'help': ('Show the differences in comparison with another project. ' - 'Argument can be map file or project directory.')}, - {'names': ['--output-file', 'output_file'], - 'help': 'Print output to the specified file instead of to the standard output'}] + size_options = [ + { + 'names': ['--format', 'output_format'], + 'type': click.Choice(['default', 'text', 'csv', 'json', 'json2', 'tree', 'raw']), + 'help': 'Specify output format: text (same as "default"), csv, json, json2, tree or raw.', + 'default': 'default', + }, + { + 'names': ['--legacy', '-l'], + 'is_flag': True, + 'default': os.environ.get('ESP_IDF_SIZE_LEGACY', '0') == '1', + 'help': 'Use legacy esp-idf-size version', + }, + { + 'names': ['--diff', 'diff_map_file'], + 'help': ( + 'Show the differences in comparison with another project. ' + 'Argument can be map file or project directory.' + ), + }, + { + 'names': ['--output-file', 'output_file'], + 'help': 'Print output to the specified file instead of to the standard output', + }, + ] build_actions = { 'actions': { @@ -437,7 +479,8 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any: 'and generate build files for the main build tool.\n\n' '3. Run the main build tool (Ninja or GNU Make). ' 'By default, the build tool is automatically detected ' - 'but it can be explicitly set by passing the -G option to idf.py.\n\n'), + 'but it can be explicitly set by passing the -G option to idf.py.\n\n' + ), 'options': global_options, 'order_dependencies': [ 'reconfigure', @@ -449,7 +492,8 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any: 'menuconfig': { 'callback': menuconfig, 'help': 'Run "menuconfig" project configuration tool.', - 'options': global_options + [ + 'options': global_options + + [ { 'names': ['--style', '--color-scheme', 'style'], 'help': ( @@ -460,7 +504,8 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any: '- aquatic - a blue theme.\n\n' 'It is possible to customize these themes further' ' as it is described in the Color schemes section of the kconfiglib documentation.\n' - 'The default value is \"aquatic\".'), + 'The default value is "aquatic".' + ), 'envvar': 'MENUCONFIG_STYLE', 'default': 'aquatic', } @@ -499,13 +544,13 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any: }, 'efuse-common-table': { 'callback': build_target, - 'help': 'Generate C-source for IDF\'s eFuse fields.', + 'help': "Generate C-source for IDF's eFuse fields.", 'order_dependencies': ['reconfigure'], 'options': global_options, }, 'efuse-custom-table': { 'callback': build_target, - 'help': 'Generate C-source for user\'s eFuse fields.', + 'help': "Generate C-source for user's eFuse fields.", 'order_dependencies': ['reconfigure'], 'options': global_options, }, @@ -534,41 +579,37 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any: 'callback': show_docs, 'help': 'Open web browser with documentation for ESP-IDF', 'options': [ - { - 'names': ['--no-browser', '-nb'], - 'is_flag': True, - 'help': 'Don\'t open browser.' - }, + {'names': ['--no-browser', '-nb'], 'is_flag': True, 'help': "Don't open browser."}, { 'names': ['--language', '-l'], 'default': get_default_language(), 'type': click.Choice(['en', 'zh_CN', 'cn']), - 'help': 'Documentation language. Your system language by default (en or cn)' + 'help': 'Documentation language. Your system language by default (en or cn)', }, { 'names': ['--starting-page', '-sp'], - 'help': 'Documentation page (get-started, api-reference etc).' - }, - { - 'names': ['--version', '-v'], - 'help': 'Version of ESP-IDF.' + 'help': 'Documentation page (get-started, api-reference etc).', }, + {'names': ['--version', '-v'], 'help': 'Version of ESP-IDF.'}, { 'names': ['--target', '-t'], 'type': TargetChoice(SUPPORTED_TARGETS + PREVIEW_TARGETS + ['']), - 'help': 'Chip target.' - } - ] + 'help': 'Chip target.', + }, + ], }, 'save-defconfig': { 'callback': save_defconfig, 'help': 'Generate a sdkconfig.defaults with options different from the default ones', - 'options': global_options + [{ - 'names': ['--add-menu-labels'], - 'is_flag': True, - 'help': 'Add menu labels to minimal config.', - }] - } + 'options': global_options + + [ + { + 'names': ['--add-menu-labels'], + 'is_flag': True, + 'help': 'Add menu labels to minimal config.', + } + ], + }, } } @@ -582,8 +623,9 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any: "This isn't necessary during normal usage, " 'but can be useful after adding/removing files from the source tree, ' 'or when modifying CMake cache variables. ' - "For example, \"idf.py -DNAME='VALUE' reconfigure\" " - 'can be used to set variable "NAME" in CMake cache to value "VALUE".'), + 'For example, "idf.py -DNAME=\'VALUE\' reconfigure" ' + 'can be used to set variable "NAME" in CMake cache to value "VALUE".' + ), 'options': global_options, 'order_dependencies': ['menuconfig', 'fullclean'], }, @@ -594,8 +636,9 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any: 'Set the chip target to build. This will remove the ' 'existing sdkconfig file and corresponding CMakeCache and ' 'create new ones according to the new target.\nFor example, ' - "\"idf.py set-target esp32\" will select esp32 as the new chip " - 'target.'), + '"idf.py set-target esp32" will select esp32 as the new chip ' + 'target.' + ), 'arguments': [ { 'names': ['idf-target'], @@ -612,7 +655,8 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any: 'Delete build output files from the build directory, ' "forcing a 'full rebuild' the next time " "the project is built. Cleaning doesn't delete " - 'CMake configuration output and some other files'), + 'CMake configuration output and some other files' + ), 'order_dependencies': ['fullclean'], }, 'fullclean': { @@ -625,7 +669,8 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any: 'CMake will configure it from scratch. ' 'Note that this option recursively deletes all files ' 'in the build directory, so use with care.' - 'Project configuration is not deleted.') + 'Project configuration is not deleted.' + ), }, 'python-clean': { 'callback': python_clean, @@ -633,7 +678,8 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any: 'help': ( 'Delete generated Python byte code from the IDF directory ' 'which may cause issues when switching between IDF and Python versions. ' - 'It is advised to run this target after switching versions.') + 'It is advised to run this target after switching versions.' + ), }, } } @@ -648,13 +694,13 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any: { 'names': ['--json', 'json_option'], 'is_flag': True, - 'help': 'Print out actions in machine-readable format for selected target.' + 'help': 'Print out actions in machine-readable format for selected target.', }, { 'names': ['--add-options'], 'is_flag': True, - 'help': 'Add options about actions to machine-readable format.' - } + 'help': 'Add options about actions to machine-readable format.', + }, ], } }