From 56f9a9f77c87d0c842853e0992a4680d74ee78ed Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Mon, 4 Nov 2024 08:55:39 +0100 Subject: [PATCH 01/11] project: Fix redundant-open-modes (UP015) Derived from pyupgrade, see https://docs.astral.sh/ruff/rules/redundant-open-modes/ Signed-off-by: Pieter De Gendt --- src/west/commands.py | 2 +- tests/test_manifest.py | 2 +- tests/test_project.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/west/commands.py b/src/west/commands.py index cad13425..baaaf798 100644 --- a/src/west/commands.py +++ b/src/west/commands.py @@ -647,7 +647,7 @@ def _ext_specs(project): continue # Load the spec file and check the schema. - with open(spec_file, 'r') as f: + with open(spec_file) as f: try: commands_spec = yaml.safe_load(f.read()) except yaml.YAMLError as e: diff --git a/tests/test_manifest.py b/tests/test_manifest.py index 9928af4e..9677bd23 100644 --- a/tests/test_manifest.py +++ b/tests/test_manifest.py @@ -3252,7 +3252,7 @@ def test_submodule_manifest(): glob(os.path.join(THIS_DIRECTORY, 'manifests', 'invalid_*.yml'))) def test_invalid(invalid): - with open(invalid, 'r') as f: + with open(invalid) as f: data = yaml.safe_load(f.read()) with pytest.raises(MalformedManifest): diff --git a/tests/test_project.py b/tests/test_project.py index 6f01fdc7..31608bc2 100644 --- a/tests/test_project.py +++ b/tests/test_project.py @@ -1805,7 +1805,7 @@ def test_init_with_manifest_filename(repos_tmpdir): west_tmpdir = repos_tmpdir / 'workspace' manifest = repos_tmpdir / 'repos' / 'zephyr' - with open(manifest / 'west.yml', 'r') as f: + with open(manifest / 'west.yml') as f: manifest_data = f.read() # also creates a west.yml with a syntax error to verify west doesn't even From 913f706b058381d59b068172e6f05f0da04538e6 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Mon, 4 Nov 2024 09:13:07 +0100 Subject: [PATCH 02/11] project: Fix non-pep585-annotation for list (UP006) Derived from pyupgrade, see https://docs.astral.sh/ruff/rules/non-pep585-annotation/ Signed-off-by: Pieter De Gendt --- src/west/app/main.py | 5 ++-- src/west/commands.py | 8 +++--- src/west/configuration.py | 6 ++--- src/west/manifest.py | 54 +++++++++++++++++++-------------------- src/west/util.py | 6 ++--- 5 files changed, 39 insertions(+), 40 deletions(-) diff --git a/src/west/app/main.py b/src/west/app/main.py index 5c4cda84..976e62eb 100755 --- a/src/west/app/main.py +++ b/src/west/app/main.py @@ -28,7 +28,6 @@ import textwrap import traceback from typing import NamedTuple, Optional -from typing import List as ListType from west import log import west.configuration @@ -65,9 +64,9 @@ class EarlyArgs(NamedTuple): command_name: Optional[str] # Other arguments are appended here. - unexpected_arguments: ListType[str] + unexpected_arguments: list[str] -def parse_early_args(argv: ListType[str]) -> EarlyArgs: +def parse_early_args(argv: list[str]) -> EarlyArgs: # Hand-rolled argument parser for early arguments. help = False diff --git a/src/west/commands.py b/src/west/commands.py index baaaf798..f6a8c0a6 100644 --- a/src/west/commands.py +++ b/src/west/commands.py @@ -18,7 +18,7 @@ import subprocess import sys from types import ModuleType -from typing import Callable, Dict, List, NoReturn, Optional +from typing import Callable, Dict, NoReturn, Optional import colorama import pykwalify @@ -149,7 +149,7 @@ def __init__(self, name: str, help: str, description: str, self.topdir: Optional[str] = None self.manifest = None self.config = None - self._hooks: List[Callable[['WestCommand'], None]] = [] + self._hooks: list[Callable[['WestCommand'], None]] = [] def add_pre_run_hook(self, hook: Callable[['WestCommand'], None]) -> None: @@ -162,7 +162,7 @@ def add_pre_run_hook(self, ''' self._hooks.append(hook) - def run(self, args: argparse.Namespace, unknown: List[str], + def run(self, args: argparse.Namespace, unknown: list[str], topdir: PathType, manifest: Optional[Manifest] = None, config: Optional[Configuration] = None) -> None: @@ -229,7 +229,7 @@ def do_add_parser(self, parser_adder) -> argparse.ArgumentParser: ''' @abstractmethod - def do_run(self, args: argparse.Namespace, unknown: List[str]): + def do_run(self, args: argparse.Namespace, unknown: list[str]): '''Subclasses must implement; called to run the command. :param args: ``argparse.Namespace`` of parsed arguments diff --git a/src/west/configuration.py b/src/west/configuration.py index 10fd8bef..0341306b 100644 --- a/src/west/configuration.py +++ b/src/west/configuration.py @@ -40,7 +40,7 @@ from pathlib import PureWindowsPath, Path import platform from enum import Enum -from typing import Any, Dict, Iterable, List, Optional, Tuple, TYPE_CHECKING, Union +from typing import Any, Dict, Iterable, Optional, Tuple, TYPE_CHECKING, Union import warnings from west.util import WEST_DIR, west_dir, WestNotFound, PathType @@ -491,7 +491,7 @@ def update_config(section: str, key: str, value: Any, config.write(f) def delete_config(section: str, key: str, - configfile: Union[Optional[ConfigFile], List[ConfigFile]] = None, + configfile: Union[Optional[ConfigFile], list[ConfigFile]] = None, topdir: Optional[PathType] = None) -> None: '''Delete the option section.key from the given file or files. @@ -626,7 +626,7 @@ def _location(cfg: ConfigFile, topdir: Optional[PathType] = None, else: raise ValueError(f'invalid configuration file {cfg}') -def _gather_configs(cfg: ConfigFile, topdir: Optional[PathType]) -> List[str]: +def _gather_configs(cfg: ConfigFile, topdir: Optional[PathType]) -> list[str]: # Find the paths to the given configuration files, in increasing # precedence order. ret = [] diff --git a/src/west/manifest.py b/src/west/manifest.py index 93d31ffd..464ae499 100644 --- a/src/west/manifest.py +++ b/src/west/manifest.py @@ -17,7 +17,7 @@ import shlex import subprocess import sys -from typing import Any, Callable, Dict, Iterable, List, NoReturn, \ +from typing import Any, Callable, Dict, Iterable, NoReturn, \ NamedTuple, Optional, Set, TYPE_CHECKING, Union from packaging.version import parse as parse_version @@ -70,11 +70,11 @@ # The value of a west-commands as passed around during manifest # resolution. It can become a list due to resolving imports, even # though it's just a str in each individual file right now. -WestCommandsType = Union[str, List[str]] +WestCommandsType = Union[str, list[str]] # Type for the importer callback passed to the manifest constructor. # (ImportedContentType is just an alias for what it gives back.) -ImportedContentType = Optional[Union[str, List[str]]] +ImportedContentType = Optional[Union[str, list[str]]] ImporterType = Callable[['Project', str], ImportedContentType] # Type for an import map filter function, which takes a Project and @@ -84,10 +84,10 @@ ImapFilterFnType = Optional[Callable[['Project'], bool]] # A list of group names to enable and disable, like ['+foo', '-bar']. -GroupFilterType = List[str] +GroupFilterType = list[str] # A list of group names belonging to a project, like ['foo', 'bar'] -GroupsType = List[str] +GroupsType = list[str] class PFR(enum.Enum): # "Project filter result": internal type for expressing whether a @@ -126,7 +126,7 @@ class ProjectFilterElt(NamedTuple): # ProjectFilterElt(re.compile('hal_my_vendor'), True)] # # The regular expression must match the entire project name. -ProjectFilterType = List[ProjectFilterElt] +ProjectFilterType = list[ProjectFilterElt] def _update_project_filter(project_filter: ProjectFilterType, option_value: Optional[str]) -> None: @@ -180,7 +180,7 @@ class Submodule(NamedTuple): name: Optional[str] = None # Submodules may be a list of values or a bool. -SubmodulesType = Union[List[Submodule], bool] +SubmodulesType = Union[list[Submodule], bool] # Manifest locating, parsing, loading, etc. @@ -209,7 +209,7 @@ def _load(data: str) -> Any: raise MalformedManifest(data) from e def _west_commands_list(west_commands: Optional[WestCommandsType]) -> \ - List[str]: + list[str]: # Convert the raw data from a manifest file to a list of # west_commands locations. (If it's already a list, make a # defensive copy.) @@ -221,7 +221,7 @@ def _west_commands_list(west_commands: Optional[WestCommandsType]) -> \ else: return list(west_commands) -def _west_commands_maybe_delist(west_commands: List[str]) -> WestCommandsType: +def _west_commands_maybe_delist(west_commands: list[str]) -> WestCommandsType: # Convert a west_commands list to a string if there's # just one element, otherwise return the list itself. @@ -230,7 +230,7 @@ def _west_commands_maybe_delist(west_commands: List[str]) -> WestCommandsType: else: return west_commands -def _west_commands_merge(wc1: List[str], wc2: List[str]) -> List[str]: +def _west_commands_merge(wc1: list[str], wc2: list[str]) -> list[str]: # Merge two west_commands lists, filtering out duplicates. if wc1 and wc2: @@ -296,10 +296,10 @@ def _manifest_content_at(project: 'Project', path: PathType, mf_encoding: str, class _import_map(NamedTuple): file: str - name_allowlist: List[str] - path_allowlist: List[str] - name_blocklist: List[str] - path_blocklist: List[str] + name_allowlist: list[str] + path_allowlist: list[str] + name_blocklist: list[str] + path_blocklist: list[str] path_prefix: str def _is_imap_list(value: Any) -> bool: @@ -320,7 +320,7 @@ def _imap_filter(imap: _import_map) -> ImapFilterFnType: else: return None -def _ensure_list(item: Union[str, List[str]]) -> List[str]: +def _ensure_list(item: Union[str, list[str]]) -> list[str]: # Converts item to a list containing it if item is a string, or # returns item. @@ -376,7 +376,7 @@ class _import_ctx(NamedTuple): # repository itself. This is mutable state in the same way # 'projects' is. Manifests which are imported earlier get # higher precedence here as usual. - manifest_west_commands: List[str] + manifest_west_commands: list[str] # The current restrictions on which projects the importing # manifest is interested in. @@ -900,7 +900,7 @@ def as_dict(self) -> Dict: # Git helpers # - def git(self, cmd: Union[str, List[str]], + def git(self, cmd: Union[str, list[str]], extra_args: Iterable[str] = (), capture_stdout: bool = False, capture_stderr: bool = False, @@ -1069,7 +1069,7 @@ def read_at(self, path: PathType, rev: Optional[str] = None, def listdir_at(self, path: PathType, rev: Optional[str] = None, cwd: Optional[PathType] = None, - encoding: Optional[str] = None) -> List[str]: + encoding: Optional[str] = None) -> list[str]: '''List of directory contents in the project at a specific revision. The return value is the directory contents as a list of files and @@ -1470,7 +1470,7 @@ def __init__(self, *, # All arguments are keyword-only. # later as needed. # This backs the projects() property. - self._projects: List[Project] = [] + self._projects: list[Project] = [] # The final set of groups which are explicitly disabled in # this manifest data, after resolving imports. This is used # as an optimization in is_active(). @@ -1529,7 +1529,7 @@ def get_projects(self, # any str name is also a PathType project_ids: Iterable[PathType], allow_paths: bool = True, - only_cloned: bool = False) -> List[Project]: + only_cloned: bool = False) -> list[Project]: '''Get a list of `Project` objects in the manifest from *project_ids*. @@ -1555,9 +1555,9 @@ def get_projects(self, :param only_cloned: raise an exception for uncloned projects ''' projects = list(self.projects) - unknown: List[PathType] = [] # project_ids with no Projects - uncloned: List[Project] = [] # if only_cloned, the uncloned Projects - ret: List[Project] = [] # result list of resolved Projects + unknown: list[PathType] = [] # project_ids with no Projects + uncloned: list[Project] = [] # if only_cloned, the uncloned Projects + ret: list[Project] = [] # result list of resolved Projects # If no project_ids are specified, use all projects. if not project_ids: @@ -1689,7 +1689,7 @@ def as_frozen_yaml(self, **kwargs) -> str: return self._dump_yaml(self.as_frozen_dict(), **kwargs) @property - def projects(self) -> List[Project]: + def projects(self) -> list[Project]: '''Sequence of `Project` objects representing manifest projects. @@ -2043,7 +2043,7 @@ def _load_group_filter(self, manifest_data: Dict[str, Any]) -> None: _logger.debug('group-filter: unset') return - raw_filter: List[RawGroupType] = manifest_data['group-filter'] + raw_filter: list[RawGroupType] = manifest_data['group-filter'] if not raw_filter: self._malformed('"manifest: group-filter:" may not be empty') @@ -2056,7 +2056,7 @@ def _load_group_filter(self, manifest_data: Dict[str, Any]) -> None: self._top_level_group_filter = group_filter def _validated_group_filter( - self, source: Optional[str], raw_filter: List[RawGroupType] + self, source: Optional[str], raw_filter: list[RawGroupType] ) -> GroupFilterType: # Helper function for cleaning up nonempty manifest: # group-filter: and manifest.group-filter values. @@ -2442,7 +2442,7 @@ def _load_project(self, pd: Dict, url_bases: Dict[str, str], return ret def _validate_project_groups(self, project_name: str, - raw_groups: List[RawGroupType]): + raw_groups: list[RawGroupType]): for raw_group in raw_groups: if not is_group(raw_group): self._malformed(f'project {project_name}: ' diff --git a/src/west/util.py b/src/west/util.py index 3a225e94..e5c05348 100644 --- a/src/west/util.py +++ b/src/west/util.py @@ -9,7 +9,7 @@ import pathlib import shlex import textwrap -from typing import List, Optional, Union +from typing import Optional, Union # What west's APIs accept for paths. # @@ -39,11 +39,11 @@ def escapes_directory(path: PathType, directory: PathType) -> bool: ret = True return ret -def quote_sh_list(cmd: List[str]) -> str: +def quote_sh_list(cmd: list[str]) -> str: '''Transform a command from list into shell string form.''' return ' '.join(shlex.quote(s) for s in cmd) -def wrap(text: str, indent: str) -> List[str]: +def wrap(text: str, indent: str) -> list[str]: '''Convenience routine for wrapping text to a consistent indent.''' return textwrap.wrap(text, initial_indent=indent, subsequent_indent=indent) From 8313ea30994d515b677b76a0d519df12bfe9dedb Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Mon, 4 Nov 2024 09:20:10 +0100 Subject: [PATCH 03/11] project: Fix non-pep585-annotation for dict (UP006) Derived from pyupgrade, see https://docs.astral.sh/ruff/rules/non-pep585-annotation/ Signed-off-by: Pieter De Gendt --- src/west/commands.py | 4 +-- src/west/configuration.py | 6 ++-- src/west/manifest.py | 58 +++++++++++++++++++-------------------- 3 files changed, 34 insertions(+), 34 deletions(-) diff --git a/src/west/commands.py b/src/west/commands.py index f6a8c0a6..d8a86240 100644 --- a/src/west/commands.py +++ b/src/west/commands.py @@ -18,7 +18,7 @@ import subprocess import sys from types import ModuleType -from typing import Callable, Dict, NoReturn, Optional +from typing import Callable, NoReturn, Optional import colorama import pykwalify @@ -41,7 +41,7 @@ # Cache which maps files implementing extension commands to their # imported modules. -_EXT_MODULES_CACHE: Dict[str, ModuleType] = {} +_EXT_MODULES_CACHE: dict[str, ModuleType] = {} # Infinite iterator of "fresh" extension command module names. _EXT_MODULES_NAME_IT = (f'west.commands.ext.cmd_{i}' for i in itertools.count(1)) diff --git a/src/west/configuration.py b/src/west/configuration.py index 0341306b..1263f49b 100644 --- a/src/west/configuration.py +++ b/src/west/configuration.py @@ -40,7 +40,7 @@ from pathlib import PureWindowsPath, Path import platform from enum import Enum -from typing import Any, Dict, Iterable, Optional, Tuple, TYPE_CHECKING, Union +from typing import Any, Iterable, Optional, Tuple, TYPE_CHECKING, Union import warnings from west.util import WEST_DIR, west_dir, WestNotFound, PathType @@ -399,8 +399,8 @@ def _local_as_dict(self): return self._cf_to_dict(self._local) @staticmethod - def _cf_to_dict(cf: Optional[_InternalCF]) -> Dict[str, Any]: - ret: Dict[str, Any] = {} + def _cf_to_dict(cf: Optional[_InternalCF]) -> dict[str, Any]: + ret: dict[str, Any] = {} if cf is None: return ret for section, contents in cf.cp.items(): diff --git a/src/west/manifest.py b/src/west/manifest.py index 464ae499..d12fa867 100644 --- a/src/west/manifest.py +++ b/src/west/manifest.py @@ -17,7 +17,7 @@ import shlex import subprocess import sys -from typing import Any, Callable, Dict, Iterable, NoReturn, \ +from typing import Any, Callable, Iterable, NoReturn, \ NamedTuple, Optional, Set, TYPE_CHECKING, Union from packaging.version import parse as parse_version @@ -166,7 +166,7 @@ def _err(message): # The parsed contents of a manifest YAML file as returned by _load(), # after sanitychecking with validate(). -ManifestDataType = Union[str, Dict] +ManifestDataType = Union[str, dict] # Logging @@ -358,7 +358,7 @@ class _import_ctx(NamedTuple): # imported earlier get higher precedence: if a 'projects:' list # contains a name which is already present here, we ignore that # element. - projects: Dict[str, 'Project'] + projects: dict[str, 'Project'] # The project filters we should apply while resolving imports. We # try to load this only once from the 'manifest.project-filter' @@ -527,7 +527,7 @@ def manifest_path() -> str: os.fspath(ret_path)) return os.fspath(ret_path) -def validate(data: Any) -> Dict[str, Any]: +def validate(data: Any) -> dict[str, Any]: '''Validate manifest data Raises an exception if the manifest data is not valid for loading @@ -863,11 +863,11 @@ def posixpath(self) -> Optional[str]: def name_and_path(self) -> str: return f'{self.name} ({self.path})' - def as_dict(self) -> Dict: + def as_dict(self) -> dict: '''Return a representation of this object as a dict, as it would be parsed from an equivalent YAML manifest. ''' - ret: Dict = {} + ret: dict = {} ret['name'] = self.name if self.description: ret['description'] = _MLS(self.description) @@ -887,7 +887,7 @@ def as_dict(self) -> Dict: elif isinstance(self.submodules, list): ret['submodules'] = [] for s in self.submodules: - obj: Dict = {'path': s.path} + obj: dict = {'path': s.path} if s.name: obj['name'] = s.name ret['submodules'].append(obj) @@ -1180,10 +1180,10 @@ def abspath(self) -> Optional[str]: self.path)) return self._abspath - def as_dict(self) -> Dict: + def as_dict(self) -> dict: '''Return a representation of this object as a dict, as it would be parsed from an equivalent YAML manifest.''' - ret: Dict = {} + ret: dict = {} if self.path: ret['path'] = self.path if self.west_commands: @@ -1592,8 +1592,8 @@ def get_projects(self, return ret def _as_dict_helper( - self, pdict: Optional[Callable[[Project], Dict]] = None) \ - -> Dict: + self, pdict: Optional[Callable[[Project], dict]] = None) \ + -> dict: # pdict: returns a Project's dict representation. # By default, it's Project.as_dict. if pdict is None: @@ -1606,7 +1606,7 @@ def _as_dict_helper( # This relies on insertion-ordered dictionaries for # predictability, which is a CPython 3.6 implementation detail # and Python 3.7+ guarantee. - r: Dict[str, Any] = {} + r: dict[str, Any] = {} r['manifest'] = {} if self.group_filter: r['manifest']['group-filter'] = self.group_filter @@ -1615,7 +1615,7 @@ def _as_dict_helper( return r - def as_dict(self) -> Dict: + def as_dict(self) -> dict: '''Returns a dict representing self, fully resolved. The value is "resolved" in that the result is as if all @@ -1624,7 +1624,7 @@ def as_dict(self) -> Dict: ''' return self._as_dict_helper() - def as_frozen_dict(self) -> Dict: + def as_frozen_dict(self) -> dict: '''Returns a dict representing self, but frozen. The value is "frozen" in that all project revisions are the @@ -1648,7 +1648,7 @@ def pdict(p): return self._as_dict_helper(pdict=pdict) - def _dump_yaml(self, to_dump: Dict, **kwargs) -> str: + def _dump_yaml(self, to_dump: dict, **kwargs) -> str: ''' Dumps dictionary to YAML using the multi-line string representer. :param dict: dictionary to be dumped @@ -2011,9 +2011,9 @@ def _load_validated(self) -> None: # that rely on the ManifestProject existing. self._projects = list(self._ctx.projects.values()) self._projects.insert(MANIFEST_PROJECT_INDEX, mp) - self._projects_by_name: Dict[str, Project] = {'manifest': mp} + self._projects_by_name: dict[str, Project] = {'manifest': mp} self._projects_by_name.update(self._ctx.projects) - self._projects_by_rpath: Dict[Path, Project] = {} # resolved paths + self._projects_by_rpath: dict[Path, Project] = {} # resolved paths if self.topdir: for p in self.projects: if TYPE_CHECKING: @@ -2036,7 +2036,7 @@ def _load_validated(self) -> None: _logger.debug(f'loaded {loading_what}') - def _load_group_filter(self, manifest_data: Dict[str, Any]) -> None: + def _load_group_filter(self, manifest_data: dict[str, Any]) -> None: # Update self._ctx.group_filter_q from manifest_data. if 'group-filter' not in manifest_data: @@ -2086,11 +2086,11 @@ def _validated_group_filter( return ret - def _load_self(self, manifest_data: Dict[str, Any]) -> None: + def _load_self(self, manifest_data: dict[str, Any]) -> None: # Handle the "self:" section in the manifest data, including # import resolution and extension commands. - slf: Optional[Dict[str, Any]] = manifest_data.get('self') + slf: Optional[dict[str, Any]] = manifest_data.get('self') if not slf: return None @@ -2224,7 +2224,7 @@ def _import_pathobj_from_self(self, pathobj_abs: Path, except RecursionError as e: raise _ManifestImportDepth(None, pathobj) from e - def _import_map_from_self(self, imp: Dict) -> None: + def _import_map_from_self(self, imp: dict) -> None: # imap may introduce additional constraints on self._ctx, such # as a stricter imap_filter or a longer path_prefix. # @@ -2262,8 +2262,8 @@ def _import_map_from_self(self, imp: Dict) -> None: except RecursionError as e: raise _ManifestImportDepth(None, import_abs) from e - def _load_defaults(self, defaults: Dict[str, Any], - url_bases: Dict[str, str]) -> _defaults: + def _load_defaults(self, defaults: dict[str, Any], + url_bases: dict[str, str]) -> _defaults: # md = manifest defaults (dictionary with values parsed from # the manifest) mdrem: Optional[str] = defaults.get('remote') @@ -2274,8 +2274,8 @@ def _load_defaults(self, defaults: Dict[str, Any], self._malformed(f'default remote {mdrem} is not defined') return _defaults(mdrem, defaults.get('revision', _DEFAULT_REV)) - def _load_projects(self, manifest: Dict[str, Any], - url_bases: Dict[str, str], + def _load_projects(self, manifest: dict[str, Any], + url_bases: dict[str, str], defaults: _defaults) -> None: # Load projects and add them to self._ctx.projects. @@ -2317,7 +2317,7 @@ def _load_projects(self, manifest: Dict[str, Any], for project, imp in have_imports: self._import_from_project(project, imp) - def _load_project(self, pd: Dict, url_bases: Dict[str, str], + def _load_project(self, pd: dict, url_bases: dict[str, str], defaults: _defaults) -> Project: # pd = project data (dictionary with values parsed from the # manifest) @@ -2537,7 +2537,7 @@ def _import_path_from_project(self, project: Project, path: str) -> None: _logger.debug(f'done resolving import {path} for {project}') def _import_map_from_project(self, project: Project, - imp: Dict) -> None: + imp: dict) -> None: imap = self._load_imap(imp, f'project {project.name}') _logger.debug(f'resolving import {imap} for {project}') @@ -2617,7 +2617,7 @@ def _import_content_from_project(self, project: Project, return content - def _load_imap(self, imp: Dict, src: str) -> _import_map: + def _load_imap(self, imp: dict, src: str) -> _import_map: # Convert a parsed self or project import value from YAML into # an _import_map namedtuple. @@ -2709,7 +2709,7 @@ def _check_project_name(self, project): 'of west') def _check_paths_are_unique(self) -> None: - ppaths: Dict[Path, Project] = {} + ppaths: dict[Path, Project] = {} for name, project in self._ctx.projects.items(): pp = Path(project.path) if self._top_level and pp == self._config_path: From 36971b5013724f4be10bff652c5b788588b418a6 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Mon, 4 Nov 2024 09:21:57 +0100 Subject: [PATCH 04/11] project: Fix non-pep585-annotation for set (UP006) Derived from pyupgrade, see https://docs.astral.sh/ruff/rules/non-pep585-annotation/ Signed-off-by: Pieter De Gendt --- src/west/manifest.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/west/manifest.py b/src/west/manifest.py index d12fa867..180ff798 100644 --- a/src/west/manifest.py +++ b/src/west/manifest.py @@ -18,7 +18,7 @@ import subprocess import sys from typing import Any, Callable, Iterable, NoReturn, \ - NamedTuple, Optional, Set, TYPE_CHECKING, Union + NamedTuple, Optional, TYPE_CHECKING, Union from packaging.version import parse as parse_version import pykwalify.core @@ -449,7 +449,7 @@ def _compose_imap_filters(imap_filter1: ImapFilterFnType, _INVALID_PROJECT_NAME_RE = re.compile(r'([/\\])') _RESERVED_PROJECT_NAME_RE = re.compile(r'[\s,]') -def _update_disabled_groups(disabled_groups: Set[str], +def _update_disabled_groups(disabled_groups: set[str], group_filter: GroupFilterType): # Update a set of disabled groups in place based on # 'group_filter'. @@ -1474,7 +1474,7 @@ def __init__(self, *, # All arguments are keyword-only. # The final set of groups which are explicitly disabled in # this manifest data, after resolving imports. This is used # as an optimization in is_active(). - self._disabled_groups: Set[str] = set() + self._disabled_groups: set[str] = set() # The "raw" (unparsed) manifest.group-filter configuration # option in the local configuration file. See # _config_group_filter(); only initialized if self._top_level From 07781fe9a06faebb9a11c35549561dc997edcfbb Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Mon, 4 Nov 2024 09:23:50 +0100 Subject: [PATCH 05/11] project: Fix non-pep585-annotation for tuple (UP006) Derived from pyupgrade, see https://docs.astral.sh/ruff/rules/non-pep585-annotation/ Signed-off-by: Pieter De Gendt --- src/west/configuration.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/west/configuration.py b/src/west/configuration.py index 1263f49b..b479ccf4 100644 --- a/src/west/configuration.py +++ b/src/west/configuration.py @@ -40,7 +40,7 @@ from pathlib import PureWindowsPath, Path import platform from enum import Enum -from typing import Any, Iterable, Optional, Tuple, TYPE_CHECKING, Union +from typing import Any, Iterable, Optional, TYPE_CHECKING, Union import warnings from west.util import WEST_DIR, west_dir, WestNotFound, PathType @@ -366,7 +366,7 @@ def load(cf: _InternalCF): load(self._local) def items(self, configfile: ConfigFile = ConfigFile.ALL - ) -> Iterable[Tuple[str, Any]]: + ) -> Iterable[tuple[str, Any]]: '''Iterator of option, value pairs.''' if configfile == ConfigFile.ALL: ret = {} From 4129e23555f7be04f222a98f11093c68d13027e2 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Mon, 4 Nov 2024 09:25:22 +0100 Subject: [PATCH 06/11] project: Fix super-call-with-parameters (UP008) Derived from pyupgrade, see https://docs.astral.sh/ruff/rules/super-call-with-parameters/ Signed-off-by: Pieter De Gendt --- src/west/app/main.py | 4 ++-- src/west/app/project.py | 2 +- src/west/commands.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/west/app/main.py b/src/west/app/main.py index 976e62eb..9536bf6a 100755 --- a/src/west/app/main.py +++ b/src/west/app/main.py @@ -921,7 +921,7 @@ def __init__(self, *args, **kwargs): # come first as our override of that method relies on it. self.west_optionals = [] self.west_app = kwargs.pop('west_app', None) - super(WestArgumentParser, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) def print_help(self, file=None, top_level=False): print(self.format_help(top_level=top_level), end='', @@ -937,7 +937,7 @@ def format_help(self, top_level=False): # one of the subcommand parsers, and we delegate to super. if not top_level: - return super(WestArgumentParser, self).format_help() + return super().format_help() # Format the help to be at most 75 columns wide, the maximum # generally recommended by typographers for readability. diff --git a/src/west/app/project.py b/src/west/app/project.py index cc918719..b806a5a8 100644 --- a/src/west/app/project.py +++ b/src/west/app/project.py @@ -554,7 +554,7 @@ class ManifestCommand(_ProjectCommand): # west.manifest.Manifest. def __init__(self): - super(ManifestCommand, self).__init__( + super().__init__( 'manifest', 'manage the west manifest', textwrap.dedent('''\ diff --git a/src/west/commands.py b/src/west/commands.py index d8a86240..3681660c 100644 --- a/src/west/commands.py +++ b/src/west/commands.py @@ -62,7 +62,7 @@ class ExtensionCommandError(CommandError): def __init__(self, **kwargs): self.hint = kwargs.pop('hint', None) - super(ExtensionCommandError, self).__init__(**kwargs) + super().__init__(**kwargs) def _no_topdir_msg(cwd, name): return f'''\ From 210cb115c3afef6a7031601c010945b022823937 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Mon, 4 Nov 2024 09:27:04 +0100 Subject: [PATCH 07/11] project: Fix quoted-annotation (UP037) Derived from pyupgrade, see https://docs.astral.sh/ruff/rules/quoted-annotation/ Signed-off-by: Pieter De Gendt --- src/west/commands.py | 2 +- src/west/manifest.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/west/commands.py b/src/west/commands.py index 3681660c..278ad709 100644 --- a/src/west/commands.py +++ b/src/west/commands.py @@ -149,7 +149,7 @@ def __init__(self, name: str, help: str, description: str, self.topdir: Optional[str] = None self.manifest = None self.config = None - self._hooks: list[Callable[['WestCommand'], None]] = [] + self._hooks: list[Callable[[WestCommand], None]] = [] def add_pre_run_hook(self, hook: Callable[['WestCommand'], None]) -> None: diff --git a/src/west/manifest.py b/src/west/manifest.py index 180ff798..674a0ebc 100644 --- a/src/west/manifest.py +++ b/src/west/manifest.py @@ -432,8 +432,8 @@ def _compose_imap_filters(imap_filter1: ImapFilterFnType, if imap_filter1 and imap_filter2: # These type annotated versions silence mypy warnings. - fn1: Callable[['Project'], bool] = imap_filter1 - fn2: Callable[['Project'], bool] = imap_filter2 + fn1: Callable[[Project], bool] = imap_filter1 + fn2: Callable[[Project], bool] = imap_filter2 return lambda project: (fn1(project) and fn2(project)) else: return imap_filter1 or imap_filter2 From 262fa8927a39826261c977d63d77952ea7f791aa Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Mon, 4 Nov 2024 09:28:29 +0100 Subject: [PATCH 08/11] project: Fix deprecated-import for Iterable (UP035) Derived from pyupgrade, see https://docs.astral.sh/ruff/rules/deprecated-import/ Signed-off-by: Pieter De Gendt --- src/west/configuration.py | 3 ++- src/west/manifest.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/west/configuration.py b/src/west/configuration.py index b479ccf4..aa220dbc 100644 --- a/src/west/configuration.py +++ b/src/west/configuration.py @@ -40,7 +40,8 @@ from pathlib import PureWindowsPath, Path import platform from enum import Enum -from typing import Any, Iterable, Optional, TYPE_CHECKING, Union +from typing import Any, Optional, TYPE_CHECKING, Union +from collections.abc import Iterable import warnings from west.util import WEST_DIR, west_dir, WestNotFound, PathType diff --git a/src/west/manifest.py b/src/west/manifest.py index 674a0ebc..3f4b7898 100644 --- a/src/west/manifest.py +++ b/src/west/manifest.py @@ -17,8 +17,9 @@ import shlex import subprocess import sys -from typing import Any, Callable, Iterable, NoReturn, \ +from typing import Any, Callable, NoReturn, \ NamedTuple, Optional, TYPE_CHECKING, Union +from collections.abc import Iterable from packaging.version import parse as parse_version import pykwalify.core From bc2f009cc6e7fa4f050b7b0385e2b52e47e975c6 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Mon, 4 Nov 2024 09:32:29 +0100 Subject: [PATCH 09/11] project: Fix unicode-kind-prefix (UP025) Derived from pyupgrade, see https://docs.astral.sh/ruff/rules/unicode-kind-prefix/ Signed-off-by: Pieter De Gendt --- src/west/manifest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/west/manifest.py b/src/west/manifest.py index 3f4b7898..3a3379dd 100644 --- a/src/west/manifest.py +++ b/src/west/manifest.py @@ -1658,7 +1658,7 @@ def _dump_yaml(self, to_dump: dict, **kwargs) -> str: def mls_representer(dumper, data): if '\n' in data: - tag = u'tag:yaml.org,2002:str' + tag = 'tag:yaml.org,2002:str' return dumper.represent_scalar(tag, data, style="|") else: return dumper.represent_str(data) From 2f220f73db91ffe9671826018a5073a2f0f1948f Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Mon, 4 Nov 2024 09:33:35 +0100 Subject: [PATCH 10/11] project: Fix f-string (UP032) Derived from pyupgrade, see https://docs.astral.sh/ruff/rules/f-string/ Signed-off-by: Pieter De Gendt --- tests/test_manifest.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_manifest.py b/tests/test_manifest.py index 9677bd23..270d859c 100644 --- a/tests/test_manifest.py +++ b/tests/test_manifest.py @@ -3162,15 +3162,15 @@ def setup_project(name, group_filter): # Schema version 0.9, group-filter is used by an import: warning. with open(manifest_repo / 'west.yml', 'w') as f: f.write(textwrap.dedent( - '''\ + f'''\ manifest: version: 0.9 projects: - name: project1 - revision: {} + revision: {sha1} url: ignored import: true - '''.format(sha1))) + ''')) m = Manifest.from_file() assert m.group_filter == [] assert hasattr(m, '_legacy_group_filter_warned') From 39c049320fa190ae4d401942d7aed16e562333a2 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Mon, 4 Nov 2024 09:38:36 +0100 Subject: [PATCH 11/11] project: Extend ruff with pyupgrade checks Check for deprecated usages in the project when running ruff check. Signed-off-by: Pieter De Gendt --- pyproject.toml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index f405e1f0..a25338d0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -44,3 +44,11 @@ include-package-data = true [tool.setuptools.packages.find] where = ["src"] namespaces = false + +[tool.ruff.lint] +extend-select = [ + "UP", # pyupgrade +] +ignore = [ + "UP027", # deprecated pyupgrade rule +]