From c65bb0b1ce7222cdb4e634feb6f21cab2d7f541d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Wed, 20 Aug 2025 19:56:18 +0200 Subject: [PATCH 1/2] PERF401: fix --- .../facts/secret_modules/password_store.py | 42 ++++++++++--------- pkgs/clan-cli/clan_cli/secrets/folders.py | 8 +--- pkgs/clan-cli/clan_cli/secrets/groups.py | 30 ++++++------- pkgs/clan-cli/clan_cli/secrets/secrets.py | 14 ++++--- .../tests/test_api_dataclass_compat.py | 2 +- .../vars/secret_modules/password_store.py | 9 ++-- pkgs/clan-cli/clan_lib/backups/list.py | 8 ++-- pkgs/clan-cli/clan_lib/flake/flake.py | 34 +++++++-------- pkgs/clan-cli/clan_lib/persist/util.py | 7 +--- 9 files changed, 75 insertions(+), 79 deletions(-) diff --git a/pkgs/clan-cli/clan_cli/facts/secret_modules/password_store.py b/pkgs/clan-cli/clan_cli/facts/secret_modules/password_store.py index e4a1c4bc9..25e4aadd9 100644 --- a/pkgs/clan-cli/clan_cli/facts/secret_modules/password_store.py +++ b/pkgs/clan-cli/clan_cli/facts/secret_modules/password_store.py @@ -74,26 +74,28 @@ class SecretStore(SecretStoreBase): check=False, ).stdout.strip(), ) - for symlink in Path(password_store).glob(f"machines/{self.machine.name}/**/*"): - if symlink.is_symlink(): - hashes.append( - subprocess.run( - nix_shell( - ["git"], - [ - "git", - "-C", - password_store, - "log", - "-1", - "--format=%H", - str(symlink), - ], - ), - stdout=subprocess.PIPE, - check=False, - ).stdout.strip(), - ) + hashes.extend( + subprocess.run( + nix_shell( + ["git"], + [ + "git", + "-C", + password_store, + "log", + "-1", + "--format=%H", + str(symlink), + ], + ), + stdout=subprocess.PIPE, + check=False, + ).stdout.strip() + for symlink in Path(password_store).glob( + f"machines/{self.machine.name}/**/*", + ) + if symlink.is_symlink() + ) # we sort the hashes to make sure that the order is always the same hashes.sort() diff --git a/pkgs/clan-cli/clan_cli/secrets/folders.py b/pkgs/clan-cli/clan_cli/secrets/folders.py index 03eca6c16..5f0274821 100644 --- a/pkgs/clan-cli/clan_cli/secrets/folders.py +++ b/pkgs/clan-cli/clan_cli/secrets/folders.py @@ -23,13 +23,9 @@ sops_groups_folder = gen_sops_subfolder("groups") def list_objects(path: Path, is_valid: Callable[[str], bool]) -> list[str]: - objs: list[str] = [] if not path.exists(): - return objs - for f in path.iterdir(): - if is_valid(f.name): - objs.append(f.name) - return objs + return [] + return [f.name for f in path.iterdir() if is_valid(f.name)] def remove_object(path: Path, name: str) -> list[Path]: diff --git a/pkgs/clan-cli/clan_cli/secrets/groups.py b/pkgs/clan-cli/clan_cli/secrets/groups.py index e245bbb51..ecb6c8214 100644 --- a/pkgs/clan-cli/clan_cli/secrets/groups.py +++ b/pkgs/clan-cli/clan_cli/secrets/groups.py @@ -64,17 +64,17 @@ def list_groups(flake_dir: Path) -> list[Group]: if not group_folder.is_dir(): continue machines_path = machines_folder(flake_dir, group.name) - machines = [] - if machines_path.is_dir(): - for f in machines_path.iterdir(): - if validate_hostname(f.name): - machines.append(f.name) + machines = ( + [f.name for f in machines_path.iterdir() if validate_hostname(f.name)] + if machines_path.is_dir() + else [] + ) users_path = users_folder(flake_dir, group.name) - users = [] - if users_path.is_dir(): - for f in users_path.iterdir(): - if VALID_USER_NAME.match(f.name): - users.append(f.name) + users = ( + [f.name for f in users_path.iterdir() if VALID_USER_NAME.match(f.name)] + if users_path.is_dir() + else [] + ) groups.append(Group(flake_dir, group.name, machines, users)) return groups @@ -268,11 +268,11 @@ def get_groups(flake_dir: Path, what: str, name: str) -> list[str]: if not groups_dir.exists(): return [] - groups = [] - for group in groups_dir.iterdir(): - if group.is_dir() and (group / what / name).is_symlink(): - groups.append(group.name) - return groups + return [ + group.name + for group in groups_dir.iterdir() + if group.is_dir() and (group / what / name).is_symlink() + ] def add_secret_command(args: argparse.Namespace) -> None: diff --git a/pkgs/clan-cli/clan_cli/secrets/secrets.py b/pkgs/clan-cli/clan_cli/secrets/secrets.py index c4f136bce..5c40013a6 100644 --- a/pkgs/clan-cli/clan_cli/secrets/secrets.py +++ b/pkgs/clan-cli/clan_cli/secrets/secrets.py @@ -41,7 +41,7 @@ log = logging.getLogger(__name__) def list_generators_secrets(generators_path: Path) -> list[Path]: - paths = [] + paths: list[Path] = [] for generator_path in generators_path.iterdir(): if not generator_path.is_dir(): continue @@ -49,11 +49,13 @@ def list_generators_secrets(generators_path: Path) -> list[Path]: def validate(generator_path: Path, name: str) -> bool: return has_secret(generator_path / name) - for obj in list_objects( - generator_path, - functools.partial(validate, generator_path), - ): - paths.append(generator_path / obj) + paths.extend( + generator_path / obj + for obj in list_objects( + generator_path, + functools.partial(validate, generator_path), + ) + ) return paths diff --git a/pkgs/clan-cli/clan_cli/tests/test_api_dataclass_compat.py b/pkgs/clan-cli/clan_cli/tests/test_api_dataclass_compat.py index 882140eec..543ce4f96 100644 --- a/pkgs/clan-cli/clan_cli/tests/test_api_dataclass_compat.py +++ b/pkgs/clan-cli/clan_cli/tests/test_api_dataclass_compat.py @@ -62,7 +62,7 @@ def find_dataclasses_in_directory( and isinstance(deco.func, ast.Name) and deco.func.id == "dataclass" ): - dataclass_files.append((file_path, node.name)) + dataclass_files.append((file_path, node.name)) # noqa: PERF401 except (SyntaxError, UnicodeDecodeError) as e: print(f"Error parsing {file_path}: {e}") diff --git a/pkgs/clan-cli/clan_cli/vars/secret_modules/password_store.py b/pkgs/clan-cli/clan_cli/vars/secret_modules/password_store.py index e44512e7c..bb857d6a7 100644 --- a/pkgs/clan-cli/clan_cli/vars/secret_modules/password_store.py +++ b/pkgs/clan-cli/clan_cli/vars/secret_modules/password_store.py @@ -164,11 +164,12 @@ class SecretStore(StoreBase): from clan_cli.vars.generator import Generator - manifest = [] generators = Generator.get_machine_generators(machine, self.flake) - for generator in generators: - for file in generator.files: - manifest.append(f"{generator.name}/{file.name}".encode()) + manifest = [ + f"{generator.name}/{file.name}".encode() + for generator in generators + for file in generator.files + ] manifest.append(git_hash) return b"\n".join(manifest) diff --git a/pkgs/clan-cli/clan_lib/backups/list.py b/pkgs/clan-cli/clan_lib/backups/list.py index 7360959cb..ddb79a795 100644 --- a/pkgs/clan-cli/clan_lib/backups/list.py +++ b/pkgs/clan-cli/clan_lib/backups/list.py @@ -14,7 +14,6 @@ class Backup: def list_provider(machine: Machine, host: Remote, provider: str) -> list[Backup]: - results = [] backup_metadata = machine.select("config.clan.core.backups") list_command = backup_metadata["providers"][provider]["list"] proc = host.run( @@ -35,8 +34,11 @@ def list_provider(machine: Machine, host: Remote, provider: str) -> list[Backup] msg = f"Failed to parse json output from provider {provider}:\n{proc.stdout}" raise ClanError(msg) from e - for archive in parsed_json: - results.append(Backup(name=archive["name"], job_name=archive.get("job_name"))) + results: list[Backup] = [] + results.extend( + Backup(name=archive["name"], job_name=archive.get("job_name")) + for archive in parsed_json + ) return results diff --git a/pkgs/clan-cli/clan_lib/flake/flake.py b/pkgs/clan-cli/clan_lib/flake/flake.py index f3b58ad92..fb7e3d568 100644 --- a/pkgs/clan-cli/clan_lib/flake/flake.py +++ b/pkgs/clan-cli/clan_lib/flake/flake.py @@ -444,8 +444,9 @@ class FlakeCacheEntry: if not isinstance(selector.value, list): msg = f"Expected list for SET selector value, got {type(selector.value)}" raise ClanError(msg) - for subselector in selector.value: - fetched_indices.append(subselector.value) + fetched_indices.extend( + subselector.value for subselector in selector.value + ) # if it's just a str, that is the index elif selector.type == SelectorType.STR: if not isinstance(selector.value, str): @@ -635,9 +636,9 @@ class FlakeCacheEntry: keys_to_select: list[str] = [] # if we want to select all keys, we take all existing sub elements if selector.type == SelectorType.ALL: - for key in self.value: - if self.value[key].exists: - keys_to_select.append(key) + keys_to_select.extend( + key for key in self.value if self.value[key].exists + ) # if we want to select a set of keys, we take the keys from the selector if selector.type == SelectorType.SET: @@ -657,9 +658,9 @@ class FlakeCacheEntry: # if we are a list, return a list if self.is_list: - result_list: list[Any] = [] - for index in keys_to_select: - result_list.append(self.value[index].select(selectors[1:])) + result_list: list[Any] = [ + self.value[index].select(selectors[1:]) for index in keys_to_select + ] return result_list # otherwise return a dict @@ -681,12 +682,10 @@ class FlakeCacheEntry: if selector.type == SelectorType.ALL: str_selector = "*" elif selector.type == SelectorType.SET: - subselectors: list[str] = [] if not isinstance(selector.value, list): msg = f"Expected list for SET selector value in error handling, got {type(selector.value)}" raise ClanError(msg) - for subselector in selector.value: - subselectors.append(subselector.value) + subselectors = [subselector.value for subselector in selector.value] str_selector = "{" + ",".join(subselectors) + "}" else: if not isinstance(selector.value, str): @@ -967,9 +966,9 @@ class Flake: nix_options = self.nix_options[:] if self.nix_options is not None else [] - str_selectors: list[str] = [] - for selector in selectors: - str_selectors.append(selectors_as_json(parse_selector(selector))) + str_selectors = [ + selectors_as_json(parse_selector(selector)) for selector in selectors + ] config = nix_config() @@ -1079,10 +1078,9 @@ class Flake: if self.flake_cache_path is None: msg = "Flake cache path cannot be None" raise ClanError(msg) - not_fetched_selectors = [] - for selector in selectors: - if not self._cache.is_cached(selector): - not_fetched_selectors.append(selector) + not_fetched_selectors = [ + selector for selector in selectors if not self._cache.is_cached(selector) + ] if not_fetched_selectors: self.get_from_nix(not_fetched_selectors) diff --git a/pkgs/clan-cli/clan_lib/persist/util.py b/pkgs/clan-cli/clan_lib/persist/util.py index ed3cc927f..a30c7d9ea 100644 --- a/pkgs/clan-cli/clan_lib/persist/util.py +++ b/pkgs/clan-cli/clan_lib/persist/util.py @@ -133,12 +133,7 @@ def list_difference(all_items: list, filter_items: list) -> list: """ # Unmerge the lists - res = [] - for value in all_items: - if value not in filter_items: - res.append(value) - - return res + return [value for value in all_items if value not in filter_items] def find_duplicates(string_list: list[str]) -> list[str]: From 7f1590c7291dc5c64a818b35b746bcb3a586079d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Wed, 20 Aug 2025 19:57:45 +0200 Subject: [PATCH 2/2] PERF403: fix --- pkgs/clan-cli/clan_cli/ssh/deploy_info.py | 5 +---- pkgs/clan-cli/openapi.py | 7 +++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/pkgs/clan-cli/clan_cli/ssh/deploy_info.py b/pkgs/clan-cli/clan_cli/ssh/deploy_info.py index cb3e0bf8d..223f7d617 100644 --- a/pkgs/clan-cli/clan_cli/ssh/deploy_info.py +++ b/pkgs/clan-cli/clan_cli/ssh/deploy_info.py @@ -58,10 +58,7 @@ def ssh_command(args: argparse.Namespace) -> None: raise ClanError(msg) # Convert ssh_option list to dictionary - ssh_options = {} - if args.ssh_option: - for name, value in args.ssh_option: - ssh_options[name] = value + ssh_options = dict(args.ssh_option) if args.ssh_option else {} remote = remote.override( host_key_check=args.host_key_check, diff --git a/pkgs/clan-cli/openapi.py b/pkgs/clan-cli/openapi.py index 726448df7..5b27ac98f 100644 --- a/pkgs/clan-cli/openapi.py +++ b/pkgs/clan-cli/openapi.py @@ -105,11 +105,10 @@ def fix_nullables(schema: dict) -> dict: if isinstance(schema, dict): if "type" in schema and schema["type"] == "null": # Convert 'type: null' to 'nullable: true' - new_schema = {"nullable": True} # Merge any other keys from original schema except type - for k, v in schema.items(): - if k != "type": - new_schema[k] = v + new_schema = {"nullable": True} | { + k: v for k, v in schema.items() if k != "type" + } return fix_nullables(new_schema) # If 'oneOf' present