From 40a645152482e7e25ca885a9f6cee14982fdce52 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 30 Jan 2026 13:04:37 +0100 Subject: [PATCH 1/2] Fix ruff errors Signed-off-by: Robert Baldyga --- connection/ssh_executor.py | 3 +- connection/utils/output.py | 5 +-- log/html_main_log.py | 4 +-- storage_devices/lvm.py | 45 +++++++++++++------------ storage_devices/nullblk.py | 3 +- test_tools/drbdadm.py | 3 +- test_tools/git.py | 3 +- test_tools/linux_packaging.py | 9 ++--- test_tools/mdadm.py | 7 ++-- test_tools/os_tools.py | 13 +++---- test_tools/peach_fuzzer/peach_fuzzer.py | 3 +- test_utils/drbd.py | 7 ++-- test_utils/dut.py | 3 +- test_utils/emergency_escape.py | 5 +-- test_utils/io_stats.py | 3 +- type_def/size.py | 15 +-------- 16 files changed, 65 insertions(+), 66 deletions(-) diff --git a/connection/ssh_executor.py b/connection/ssh_executor.py index 4f4bfa8..40e4ede 100644 --- a/connection/ssh_executor.py +++ b/connection/ssh_executor.py @@ -1,6 +1,7 @@ # # Copyright(c) 2019-2021 Intel Corporation # Copyright(c) 2024 Huawei Technologies Co., Ltd. +# Copyright(c) 2026 Unvertical # SPDX-License-Identifier: BSD-3-Clause # @@ -264,5 +265,5 @@ def resolve_ip_address(self): pattern, completed_process.stdout + completed_process.stderr, re.MULTILINE ) return matches[-1].decode("utf-8") - except: + except Exception: return None diff --git a/connection/utils/output.py b/connection/utils/output.py index d3ae9ae..08055c3 100644 --- a/connection/utils/output.py +++ b/connection/utils/output.py @@ -1,6 +1,7 @@ # # Copyright(c) 2019-2021 Intel Corporation # Copyright(c) 2024 Huawei Technologies Co., Ltd. +# Copyright(c) 2026 Unvertical # SPDX-License-Identifier: BSD-3-Clause # @@ -8,9 +9,9 @@ class Output: def __init__(self, output_out, output_err, return_code): self.stdout = output_out.decode('utf-8', errors="ignore").rstrip() if \ - type(output_out) == bytes else output_out + isinstance(output_out, bytes) else output_out self.stderr = output_err.decode('utf-8', errors="ignore").rstrip() if \ - type(output_err) == bytes else output_err + isinstance(output_err, bytes) else output_err self.exit_code = return_code def __str__(self): diff --git a/log/html_main_log.py b/log/html_main_log.py index f19f070..bc70271 100644 --- a/log/html_main_log.py +++ b/log/html_main_log.py @@ -1,5 +1,6 @@ # # Copyright(c) 2019-2021 Intel Corporation +# Copyright(c) 2026 Unvertical # SPDX-License-Identifier: BSD-3-Clause # @@ -26,9 +27,6 @@ def add_build_info(self, message): def start_iteration(self, iteration_id): self.__current_iteration_id = iteration_id - def end_iteration(self): - pass - def end_iteration(self, iteration_result): root = self.get_root() iteration_selector_div = root.xpath('/html/body/div/div/div[@id="iteration-selector"]') diff --git a/storage_devices/lvm.py b/storage_devices/lvm.py index 2e94fdd..8d31090 100644 --- a/storage_devices/lvm.py +++ b/storage_devices/lvm.py @@ -1,6 +1,7 @@ # # Copyright(c) 2022 Intel Corporation # Copyright(c) 2024 Huawei Technologies Co., Ltd. +# Copyright(c) 2026 Unvertical # SPDX-License-Identifier: BSD-3-Clause # @@ -57,15 +58,15 @@ def __add_block_dev_to_lvm_config( TestRun.LOGGER.info(f"Device type '{block_device_type}' already present in config") return - TestRun.LOGGER.info(f"Add block device type to existing list") + TestRun.LOGGER.info("Add block device type to existing list") new_type_prefix = f"types = [\"{block_device_type}\", {number_of_partitions}, " config_update_cmd = f"sed -i 's/{types_prototype_regex}/\t{new_type_prefix}/g'" \ f" {lvm_config_path}" else: - TestRun.LOGGER.info(f"Create new types variable") + TestRun.LOGGER.info("Create new types variable") new_types = f"types = [\"{block_device_type}\", {number_of_partitions}]" - characteristic_line = f"# Configuration option devices\\/sysfs_scan." + characteristic_line = "# Configuration option devices\\/sysfs_scan." config_update_cmd = f"sed -i /'{characteristic_line}'/i\\ '{tab}{new_types}' " \ f"{lvm_config_path}" @@ -79,7 +80,7 @@ def __add_filter_to_lvm_config( filter: str ): if filter is None: - TestRun.LOGGER.error(f"Lvm filter for lvm config not provided.") + TestRun.LOGGER.error("Lvm filter for lvm config not provided.") filters_definition = cls.read_filter_definition_from_lvm_config() @@ -91,13 +92,13 @@ def __add_filter_to_lvm_config( new_filter_formatted = filter.replace("/", "\\/") new_filter_prefix = f"filter = [ \"{new_filter_formatted}\", " - TestRun.LOGGER.info(f"Adding filter to existing list") + TestRun.LOGGER.info("Adding filter to existing list") config_update_cmd = f"sed -i 's/{filter_prototype_regex}/\t{new_filter_prefix}/g'" \ f" {lvm_config_path}" else: - TestRun.LOGGER.info(f"Create new filter variable") + TestRun.LOGGER.info("Create new filter variable") new_filter = f"filter = [\"{filter}\"]" - characteristic_line = f"# Configuration option devices\\/global_filter." + characteristic_line = "# Configuration option devices\\/global_filter." config_update_cmd = f"sed -i /'{characteristic_line}'/i\\ '{tab}{new_filter}' " \ f"{lvm_config_path}" @@ -122,7 +123,7 @@ def add_block_device_to_lvm_config( device_type: str ): if device_type is None: - TestRun.LOGGER.error(f"No device provided.") + TestRun.LOGGER.error("No device provided.") cls.__add_block_dev_to_lvm_config(device_type) @@ -132,7 +133,7 @@ def add_filters_to_lvm_config( filters: [] ): if filters is None: - raise ValueError(f"Lvm filters for lvm config not provided.") + raise ValueError("Lvm filters for lvm config not provided.") for f in filters: cls.__add_filter_to_lvm_config(f) @@ -143,7 +144,7 @@ def configure_filters( lvm_filters: [], ): if lvm_filters: - TestRun.LOGGER.info(f"Preparing configuration for LVMs - filters.") + TestRun.LOGGER.info("Preparing configuration for LVMs - filters.") LvmConfiguration.add_filters_to_lvm_config(lvm_filters) os_disk_filters = [ @@ -151,7 +152,7 @@ def configure_filters( ] if Lvm.get_os_vg() else None if os_disk_filters: - TestRun.LOGGER.info(f"Add OS disks to LVM filters.") + TestRun.LOGGER.info("Add OS disks to LVM filters.") LvmConfiguration.add_filters_to_lvm_config(os_disk_filters) @staticmethod @@ -192,7 +193,7 @@ def __get_vg_name(cls, prefix: str = "vg"): @staticmethod def get_all_volume_groups(): - output_lines = TestRun.executor.run(f"pvscan").stdout.splitlines() + output_lines = TestRun.executor.run("pvscan").stdout.splitlines() volume_groups = {} for line in output_lines: @@ -236,7 +237,7 @@ def is_vg_already_present(cls, dev_number: int, device_paths: str = None): for vg in volume_groups: for pv in volume_groups[vg]: if pv in device_paths: - TestRun.LOGGER.warning(f"Some devices are used in other LVM volume group") + TestRun.LOGGER.warning("Some devices are used in other LVM volume group") return False @classmethod @@ -325,7 +326,7 @@ def configure_global_filter( pv_devs = [pv_devs] if global_filter_def: - TestRun.LOGGER.info(f"Configure 'global filter' variable") + TestRun.LOGGER.info("Configure 'global filter' variable") links = [] for pv_dev in pv_devs: link = pv_dev.get_device_link("/dev/disk/by-id") @@ -350,17 +351,17 @@ def configure_global_filter( global_filter += ", " global_filter = global_filter[:-2] - TestRun.LOGGER.info(f"Create new 'global filter' variable") + TestRun.LOGGER.info("Create new 'global filter' variable") new_global = f"global_filter = [{global_filter}]" - characteristic_line = f"# Configuration option devices\\/types." + characteristic_line = "# Configuration option devices\\/types." config_update_cmd = f"sed -i /'{characteristic_line}'/i\\ " \ f"'{tab}{new_global}' {lvm_config_path}" TestRun.LOGGER.info(f"Adding global filter '{global_filter}' to {lvm_config_path}") TestRun.executor.run(config_update_cmd) - TestRun.LOGGER.info(f"Remove 'filter' in order to 'global_filter' to be used") + TestRun.LOGGER.info("Remove 'filter' in order to 'global_filter' to be used") if LvmConfiguration.read_filter_definition_from_lvm_config(): LvmConfiguration.remove_filters_from_config() @@ -410,7 +411,7 @@ def create( elif isinstance(volume_size_or_percent, int): size_cmd = f"--extents {volume_size_or_percent}%VG" else: - raise ValueError(f"Incorrect type of the first argument (volume_size_or_percent).") + raise ValueError("Incorrect type of the first argument (volume_size_or_percent).") if not name: name = cls.__get_unique_lv_name() @@ -450,7 +451,7 @@ def discover_logical_volumes(cls): ) ) else: - TestRun.LOGGER.info(f"No LVMs present in the system.") + TestRun.LOGGER.info("No LVMs present in the system.") return volumes @@ -503,7 +504,7 @@ def remove_all(cls): TestRun.executor.run(f"vgchange -an {vg_name}") VolumeGroup.remove(vg_name) - cmd = f"pvdisplay | grep 'PV Name' | awk '{{print $3}}'" + cmd = "pvdisplay | grep 'PV Name' | awk '{{print $3}}'" os_disks = get_system_disks() # invert grep to make sure os_disks won`t be wiped during lvms cleanup cmd += "".join([f" | grep -v {os_disk}" for os_disk in os_disks]) @@ -511,11 +512,11 @@ def remove_all(cls): for pv_name in pv_names: cls.remove_pv(pv_name) - TestRun.LOGGER.info(f"Successfully removed all LVMs.") + TestRun.LOGGER.info("Successfully removed all LVMs.") @staticmethod def make_sure_lv_is_active(lv_path: str): - cmd = f"lvscan" + cmd = "lvscan" output_lines = TestRun.executor.run_expect_success(cmd).stdout.splitlines() for line in output_lines: diff --git a/storage_devices/nullblk.py b/storage_devices/nullblk.py index fd43cc2..316a0bc 100644 --- a/storage_devices/nullblk.py +++ b/storage_devices/nullblk.py @@ -1,5 +1,6 @@ # # Copyright(c) 2024 Huawei Technologies Co., Ltd. +# Copyright(c) 2026 Unvertical # SPDX-License-Identifier: BSD-3-Clause # @@ -44,7 +45,7 @@ def list(cls): @staticmethod def _list_devices(): - ls_output = ls(f"/dev/nullb*") + ls_output = ls("/dev/nullb*") if "No such file or directory" in ls_output: return [] return parse_ls_output(ls_output) diff --git a/test_tools/drbdadm.py b/test_tools/drbdadm.py index 8213e91..3570105 100644 --- a/test_tools/drbdadm.py +++ b/test_tools/drbdadm.py @@ -1,5 +1,6 @@ # # Copyright(c) 2022 Intel Corporation +# Copyright(c) 2026 Unvertical # SPDX-License-Identifier: BSD-3-Clause-Clear # @@ -22,7 +23,7 @@ def up(resource_name: str): # disable resource @staticmethod def down_all(): - cmd = f"drbdadm down all" + cmd = "drbdadm down all" return TestRun.executor.run_expect_success(cmd) @staticmethod diff --git a/test_tools/git.py b/test_tools/git.py index 456c08a..cf25a82 100644 --- a/test_tools/git.py +++ b/test_tools/git.py @@ -1,6 +1,7 @@ # # Copyright(c) 2019-2022 Intel Corporation # Copyright(c) 2024 Huawei Technologies Co., Ltd. +# Copyright(c) 2026 Unvertical # SPDX-License-Identifier: BSD-3-Clause # @@ -118,4 +119,4 @@ def checkout_version(version): f"cd {TestRun.usr.working_dir} && " f"git submodule update --force") if output.exit_code != 0: - raise CmdException(f"Failed to update submodules", output) + raise CmdException("Failed to update submodules", output) diff --git a/test_tools/linux_packaging.py b/test_tools/linux_packaging.py index b5a8173..c665fe2 100644 --- a/test_tools/linux_packaging.py +++ b/test_tools/linux_packaging.py @@ -1,6 +1,7 @@ # # Copyright(c) 2022 Intel Corporation # Copyright(c) 2024 Huawei Technologies Co., Ltd. +# Copyright(c) 2026 Unvertical # SPDX-License-Identifier: BSD-3-Clause # @@ -27,7 +28,7 @@ def check_if_installed(self): return output.exit_code == 0 def install(self): - TestRun.LOGGER.info(f"Installing RPM packages") + TestRun.LOGGER.info("Installing RPM packages") if not self.packages: raise ValueError("No packages given.") @@ -43,7 +44,7 @@ def install(self): raise CmdException("Installation failed or errors found during the process.", output) def uninstall(self): - TestRun.LOGGER.info(f"Uninstalling RPM packages") + TestRun.LOGGER.info("Uninstalling RPM packages") if not self.check_if_installed(): raise FileNotFoundError("Could not uninstall - packages not installed yet.") @@ -82,7 +83,7 @@ def check_if_installed(self): return output.exit_code == 0 def install(self): - TestRun.LOGGER.info(f"Installing DEB packages") + TestRun.LOGGER.info("Installing DEB packages") if not self.packages: raise ValueError("No packages given.") @@ -98,7 +99,7 @@ def install(self): raise CmdException("Installation failed or errors found during the process.", output) def uninstall(self): - TestRun.LOGGER.info(f"Uninstalling DEB packages") + TestRun.LOGGER.info("Uninstalling DEB packages") if not self.check_if_installed(): raise FileNotFoundError("Could not uninstall - packages not installed yet.") diff --git a/test_tools/mdadm.py b/test_tools/mdadm.py index 564a428..9e02bf0 100644 --- a/test_tools/mdadm.py +++ b/test_tools/mdadm.py @@ -1,6 +1,7 @@ # # Copyright(c) 2020-2021 Intel Corporation # Copyright(c) 2024 Huawei Technologies Co., Ltd. +# Copyright(c) 2026 Unvertical # SPDX-License-Identifier: BSD-3-Clause # @@ -14,7 +15,7 @@ class Mdadm: @staticmethod def assemble(device_paths: str = None): - cmd = f"mdadm --assemble " + (device_paths if device_paths else "--scan") + cmd = "mdadm --assemble " + (device_paths if device_paths else "--scan") return TestRun.executor.run(cmd) @staticmethod @@ -71,7 +72,7 @@ def detail_result(cls, raid_device_paths: str): @staticmethod def examine(brief: bool = True, device_paths: str = None): - cmd = f"mdadm --examine " + cmd = "mdadm --examine " if brief: cmd += "--brief " cmd += (device_paths if device_paths else "--scan") @@ -109,7 +110,7 @@ def examine_result(cls, device_paths: str = None): @staticmethod def stop(device_paths: str = None): - cmd = f"mdadm --stop " + (device_paths if device_paths else "--scan") + cmd = "mdadm --stop " + (device_paths if device_paths else "--scan") return TestRun.executor.run_expect_success(cmd) @staticmethod diff --git a/test_tools/os_tools.py b/test_tools/os_tools.py index 35fab60..e087448 100644 --- a/test_tools/os_tools.py +++ b/test_tools/os_tools.py @@ -1,6 +1,7 @@ # # Copyright(c) 2019-2022 Intel Corporation # Copyright(c) 2024-2025 Huawei Technologies Co., Ltd. +# Copyright(c) 2026 Unvertical # SPDX-License-Identifier: BSD-3-Clause # @@ -66,7 +67,7 @@ def drop_caches(level: DropCachesMode = DropCachesMode.ALL): def get_number_of_processors_from_cpuinfo(): """Returns number of processors (count) which are listed out in /proc/cpuinfo""" - cmd = f"cat /proc/cpuinfo | grep processor | wc -l" + cmd = "cat /proc/cpuinfo | grep processor | wc -l" output = TestRun.executor.run(cmd).stdout return int(output) @@ -157,13 +158,13 @@ def kill_all_io(graceful=True): TestRun.executor.run("kill -9 `ps aux | grep -i vdbench.* | awk '{ print $2 }'`") if TestRun.executor.run("pgrep -x dd").exit_code == 0: - raise Exception(f"Failed to stop dd!") + raise Exception("Failed to stop dd!") if TestRun.executor.run("pgrep -x fio").exit_code == 0: - raise Exception(f"Failed to stop fio!") + raise Exception("Failed to stop fio!") if TestRun.executor.run("pgrep -x blktrace").exit_code == 0: - raise Exception(f"Failed to stop blktrace!") + raise Exception("Failed to stop blktrace!") if TestRun.executor.run("pgrep vdbench").exit_code == 0: - raise Exception(f"Failed to stop vdbench!") + raise Exception("Failed to stop vdbench!") def sync(): @@ -212,7 +213,7 @@ def get_wbt_lat(device: Device): def get_cores_ids_range(numa_node: int): - output = TestRun.executor.run_expect_success(f"lscpu --all --parse").stdout + output = TestRun.executor.run_expect_success("lscpu --all --parse").stdout parse_output = re.findall(r'(\d+),(\d+),(?:\d+),(\d+),,', output, re.I) return [element[0] for element in parse_output if int(element[2]) == numa_node] diff --git a/test_tools/peach_fuzzer/peach_fuzzer.py b/test_tools/peach_fuzzer/peach_fuzzer.py index 116e3b7..c51fec4 100644 --- a/test_tools/peach_fuzzer/peach_fuzzer.py +++ b/test_tools/peach_fuzzer/peach_fuzzer.py @@ -1,6 +1,7 @@ # # Copyright(c) 2021 Intel Corporation # Copyright(c) 2024 Huawei Technologies Co., Ltd. +# Copyright(c) 2026 Unvertical # SPDX-License-Identifier: BSD-3-Clause # @@ -47,7 +48,7 @@ def get_fuzzed_command(cls, command_template: str, count: int): :returns: named tuple with fuzzed param and CLI ready to be executed with Test-Framework executors. Param is returned in order to implement correct values checkers in the tests """ - TestRun.LOGGER.info(f"Try to get commands with fuzzed parameters") + TestRun.LOGGER.info("Try to get commands with fuzzed parameters") FuzzedCommand = namedtuple('FuzzedCommand', ['param', 'command']) command_template = command_template.encode("ascii") if cls.tested_param_placeholder not in command_template: diff --git a/test_utils/drbd.py b/test_utils/drbd.py index c1b1ddb..e747bf1 100644 --- a/test_utils/drbd.py +++ b/test_utils/drbd.py @@ -1,5 +1,6 @@ # # Copyright(c) 2022 Intel Corporation +# Copyright(c) 2026 Unvertical # SPDX-License-Identifier: BSD-3-Clause-Clear # @@ -21,12 +22,12 @@ def __str__(self): ) if self.options: - output += f" options {{\n" + output += " options {{\n" for (k, v) in self.options.items(): output += f" {k} {v};\n" - output += f" }}\n" + output += " }}\n" - output += f"}}" + output += "}}" return output def __repr__(self): diff --git a/test_utils/dut.py b/test_utils/dut.py index 804dadb..c7ebee4 100644 --- a/test_utils/dut.py +++ b/test_utils/dut.py @@ -1,6 +1,7 @@ # # Copyright(c) 2019-2021 Intel Corporation # Copyright(c) 2023-2024 Huawei Technologies Co., Ltd. +# Copyright(c) 2026 Unvertical # SPDX-License-Identifier: BSD-3-Clause # @@ -46,7 +47,7 @@ def __str__(self): if (self.virsh is not None) else "" ) - dut_str += f"disks:\n" + dut_str += "disks:\n" for disk in self.disks: dut_str += f"\t{disk}" dut_str += "\n" diff --git a/test_utils/emergency_escape.py b/test_utils/emergency_escape.py index ba98167..b6d23c1 100644 --- a/test_utils/emergency_escape.py +++ b/test_utils/emergency_escape.py @@ -1,6 +1,7 @@ # # Copyright(c) 2022 Intel Corporation # Copyright(c) 2025 Huawei Corporation +# Copyright(c) 2026 Unvertical # SPDX-License-Identifier: BSD-3-Clause # @@ -95,8 +96,8 @@ def cleanup(self): @classmethod def verify_trigger_in_log(cls, log_list): - for l in log_list: - if cls.escape_marker in l: + for log in log_list: + if cls.escape_marker in log: return True return False diff --git a/test_utils/io_stats.py b/test_utils/io_stats.py index fb9607d..711d4c0 100644 --- a/test_utils/io_stats.py +++ b/test_utils/io_stats.py @@ -1,5 +1,6 @@ # # Copyright(c) 2020-2021 Intel Corporation +# Copyright(c) 2026 Unvertical # SPDX-License-Identifier: BSD-3-Clause # import re @@ -77,7 +78,7 @@ def parse(stats_line: str): elif re.match(PROCFS_LINE_FORMAT, stats_line): fields = stats_line.split()[3:] else: - raise Exception(f"Wrong input format for diskstat parser") + raise Exception("Wrong input format for diskstat parser") values = [int(f) for f in fields] diff --git a/type_def/size.py b/type_def/size.py index a0bd5e3..edcffe5 100644 --- a/type_def/size.py +++ b/type_def/size.py @@ -1,6 +1,7 @@ # # Copyright(c) 2019-2021 Intel Corporation # Copyright(c) 2024 Huawei Technologies Co., Ltd. +# Copyright(c) 2026 Unvertical # SPDX-License-Identifier: BSD-3-Clause # @@ -171,14 +172,6 @@ def __sub__(self, other): self.unit if self.unit.get_value() < other.unit.get_value() else other.unit ) - @multimethod - def __mul__(self, other: int): - return Size(math.ceil(self.get_value() * other)) - - @multimethod - def __rmul__(self, other: int): - return Size(math.ceil(self.get_value() * other)) - @multimethod def __mul__(self, other: float): return Size(math.ceil(self.get_value() * other)) @@ -187,12 +180,6 @@ def __mul__(self, other: float): def __rmul__(self, other: float): return Size(math.ceil(self.get_value() * other)) - @multimethod - def __truediv__(self, other): - if other.get_value() == 0: - raise ValueError("Divisor must not be equal to 0.") - return self.get_value() / other.get_value() - @multimethod def __truediv__(self, other: int): if other == 0: From 804ee527f7144a81e2ae474eef83fa423cd71000 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 30 Jan 2026 13:11:08 +0100 Subject: [PATCH 2/2] Fix SPDX tag Signed-off-by: Robert Baldyga --- storage_devices/drbd.py | 3 ++- test_tools/drbdadm.py | 2 +- test_utils/drbd.py | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/storage_devices/drbd.py b/storage_devices/drbd.py index a8e2ba8..20930bf 100644 --- a/storage_devices/drbd.py +++ b/storage_devices/drbd.py @@ -1,6 +1,7 @@ # # Copyright(c) 2022 Intel Corporation -# SPDX-License-Identifier: BSD-3-Clause-Clear +# Copyright(c) 2026 Unvertical +# SPDX-License-Identifier: BSD-3-Clause # import posixpath diff --git a/test_tools/drbdadm.py b/test_tools/drbdadm.py index 3570105..957e1c3 100644 --- a/test_tools/drbdadm.py +++ b/test_tools/drbdadm.py @@ -1,7 +1,7 @@ # # Copyright(c) 2022 Intel Corporation # Copyright(c) 2026 Unvertical -# SPDX-License-Identifier: BSD-3-Clause-Clear +# SPDX-License-Identifier: BSD-3-Clause # from core.test_run import TestRun diff --git a/test_utils/drbd.py b/test_utils/drbd.py index e747bf1..c882826 100644 --- a/test_utils/drbd.py +++ b/test_utils/drbd.py @@ -1,7 +1,7 @@ # # Copyright(c) 2022 Intel Corporation # Copyright(c) 2026 Unvertical -# SPDX-License-Identifier: BSD-3-Clause-Clear +# SPDX-License-Identifier: BSD-3-Clause # from test_utils.filesystem.file import File