scripts: Fix twisterlib for ruff - UP030, UP031, UP032

Fixes ruff linting errors UP030, UP031, UP032,
which make you use format specifiers (fstrings)
instead of printf formatting or str.format().

Signed-off-by: Lukasz Mrugala <lukaszx.mrugala@intel.com>
This commit is contained in:
Lukasz Mrugala 2024-11-27 16:57:32 +00:00 committed by Carles Cufí
commit 9b4397a764
18 changed files with 215 additions and 226 deletions

View file

@ -758,78 +758,54 @@
]
"./scripts/pylib/twister/twisterlib/cmakecache.py" = [
"E501", # https://docs.astral.sh/ruff/rules/line-too-long
"UP032", # https://docs.astral.sh/ruff/rules/f-string
]
"./scripts/pylib/twister/twisterlib/config_parser.py" = [
"UP007", # https://docs.astral.sh/ruff/rules/non-pep604-annotation
"UP031", # https://docs.astral.sh/ruff/rules/printf-string-formatting
]
"./scripts/pylib/twister/twisterlib/coverage.py" = [
"E501", # https://docs.astral.sh/ruff/rules/line-too-long
"UP031", # https://docs.astral.sh/ruff/rules/printf-string-formatting
"UP032", # https://docs.astral.sh/ruff/rules/f-string
]
"./scripts/pylib/twister/twisterlib/environment.py" = [
"E501", # https://docs.astral.sh/ruff/rules/line-too-long
"UP031", # https://docs.astral.sh/ruff/rules/printf-string-formatting
]
"./scripts/pylib/twister/twisterlib/handlers.py" = [
"E501", # https://docs.astral.sh/ruff/rules/line-too-long
"UP007", # https://docs.astral.sh/ruff/rules/non-pep604-annotation
"UP030", # https://docs.astral.sh/ruff/rules/format-literals
"UP031", # https://docs.astral.sh/ruff/rules/printf-string-formatting
"UP032", # https://docs.astral.sh/ruff/rules/f-string
]
"./scripts/pylib/twister/twisterlib/hardwaremap.py" = [
"E501", # https://docs.astral.sh/ruff/rules/line-too-long
"UP031", # https://docs.astral.sh/ruff/rules/printf-string-formatting
]
"./scripts/pylib/twister/twisterlib/harness.py" = [
"E501", # https://docs.astral.sh/ruff/rules/line-too-long
"UP031", # https://docs.astral.sh/ruff/rules/printf-string-formatting
"UP032", # https://docs.astral.sh/ruff/rules/f-string
]
"./scripts/pylib/twister/twisterlib/platform.py" = [
"E501", # https://docs.astral.sh/ruff/rules/line-too-long
"UP031", # https://docs.astral.sh/ruff/rules/printf-string-formatting
]
"./scripts/pylib/twister/twisterlib/quarantine.py" = [
"E501", # https://docs.astral.sh/ruff/rules/line-too-long
"UP031", # https://docs.astral.sh/ruff/rules/printf-string-formatting
]
"./scripts/pylib/twister/twisterlib/reports.py" = [
"E501", # https://docs.astral.sh/ruff/rules/line-too-long
"UP031", # https://docs.astral.sh/ruff/rules/printf-string-formatting
"UP032", # https://docs.astral.sh/ruff/rules/f-string
]
"./scripts/pylib/twister/twisterlib/runner.py" = [
"E501", # https://docs.astral.sh/ruff/rules/line-too-long
"UP031", # https://docs.astral.sh/ruff/rules/printf-string-formatting
"UP032", # https://docs.astral.sh/ruff/rules/f-string
]
"./scripts/pylib/twister/twisterlib/size_calc.py" = [
"E501", # https://docs.astral.sh/ruff/rules/line-too-long
"UP031", # https://docs.astral.sh/ruff/rules/printf-string-formatting
]
"./scripts/pylib/twister/twisterlib/testinstance.py" = [
"E501", # https://docs.astral.sh/ruff/rules/line-too-long
"UP031", # https://docs.astral.sh/ruff/rules/printf-string-formatting
]
"./scripts/pylib/twister/twisterlib/testplan.py" = [
"E402", # https://docs.astral.sh/ruff/rules/module-import-not-at-top-of-file
"E501", # https://docs.astral.sh/ruff/rules/line-too-long
"F401", # https://docs.astral.sh/ruff/rules/unused-import
"UP031", # https://docs.astral.sh/ruff/rules/printf-string-formatting
"UP032", # https://docs.astral.sh/ruff/rules/f-string
]
"./scripts/pylib/twister/twisterlib/testsuite.py" = [
"E501", # https://docs.astral.sh/ruff/rules/line-too-long
"UP031", # https://docs.astral.sh/ruff/rules/printf-string-formatting
"UP032", # https://docs.astral.sh/ruff/rules/f-string
]
"./scripts/pylib/twister/twisterlib/twister_main.py" = [
"E501", # https://docs.astral.sh/ruff/rules/line-too-long
"UP032", # https://docs.astral.sh/ruff/rules/f-string
]
"./scripts/pylint/checkers/argparse-checker.py" = [
"F821", # https://docs.astral.sh/ruff/rules/undefined-name

View file

@ -59,7 +59,7 @@ class CMakeCacheEntry:
v = int(val)
return v != 0
except ValueError as exc:
raise ValueError('invalid bool {}'.format(val)) from exc
raise ValueError(f'invalid bool {val}') from exc
@classmethod
def from_line(cls, line, line_no):
@ -81,7 +81,7 @@ class CMakeCacheEntry:
try:
value = cls._to_bool(value)
except ValueError as exc:
args = exc.args + ('on line {}: {}'.format(line_no, line),)
args = exc.args + (f'on line {line_no}: {line}',)
raise ValueError(args) from exc
# If the value is a CMake list (i.e. is a string which contains a ';'),
# convert to a Python list.

View file

@ -164,8 +164,7 @@ class TwisterConfigParser:
elif typestr.startswith("map"):
return value
else:
raise ConfigurationError(
self.filename, "unknown type '%s'" % value)
raise ConfigurationError(self.filename, f"unknown type '{value}'")
def get_scenario(self, name):
"""Get a dictionary representing the keys/values within a scenario
@ -199,7 +198,7 @@ class TwisterConfigParser:
)
if k in d:
if k == "filter":
d[k] = "(%s) and (%s)" % (d[k], v)
d[k] = f"({d[k]}) and ({v})"
elif k not in ("extra_conf_files", "extra_overlay_confs",
"extra_dtc_overlay_files"):
if isinstance(d[k], str) and isinstance(v, list):
@ -258,8 +257,8 @@ class TwisterConfigParser:
if required:
raise ConfigurationError(
self.filename,
"missing required value for '%s' in test '%s'" %
(k, name))
f"missing required value for '{k}' in test '{name}'"
)
else:
if "default" in kinfo:
default = kinfo["default"]
@ -271,8 +270,8 @@ class TwisterConfigParser:
d[k] = self._cast_value(d[k], kinfo["type"])
except ValueError:
raise ConfigurationError(
self.filename, "bad %s value '%s' for key '%s' in name '%s'" %
(kinfo["type"], d[k], k, name)
self.filename,
f"bad {kinfo['type']} value '{d[k]}' for key '{k}' in name '{name}'"
) from None
return d

View file

@ -39,7 +39,7 @@ class CoverageTool:
elif tool == 'gcovr':
t = Gcovr()
else:
logger.error("Unsupported coverage tool specified: {}".format(tool))
logger.error(f"Unsupported coverage tool specified: {tool}")
return None
logger.debug(f"Select {tool} as the coverage tool...")
@ -47,7 +47,7 @@ class CoverageTool:
@staticmethod
def retrieve_gcov_data(input_file):
logger.debug("Working on %s" % input_file)
logger.debug(f"Working on {input_file}")
extracted_coverage_info = {}
capture_data = False
capture_complete = False
@ -125,47 +125,61 @@ class CoverageTool:
with open(filename, 'wb') as fp:
fp.write(hex_bytes)
except ValueError:
logger.exception("Unable to convert hex data for file: {}".format(filename))
logger.exception(f"Unable to convert hex data for file: {filename}")
gcda_created = False
except FileNotFoundError:
logger.exception("Unable to create gcda file: {}".format(filename))
logger.exception(f"Unable to create gcda file: {filename}")
gcda_created = False
return gcda_created
def generate(self, outdir):
coverage_completed = True
for filename in glob.glob("%s/**/handler.log" % outdir, recursive=True):
for filename in glob.glob(f"{outdir}/**/handler.log", recursive=True):
gcov_data = self.__class__.retrieve_gcov_data(filename)
capture_complete = gcov_data['complete']
extracted_coverage_info = gcov_data['data']
if capture_complete:
gcda_created = self.create_gcda_files(extracted_coverage_info)
if gcda_created:
logger.debug("Gcov data captured: {}".format(filename))
logger.debug(f"Gcov data captured: {filename}")
else:
logger.error("Gcov data invalid for: {}".format(filename))
logger.error(f"Gcov data invalid for: {filename}")
coverage_completed = False
else:
logger.error("Gcov data capture incomplete: {}".format(filename))
logger.error(f"Gcov data capture incomplete: {filename}")
coverage_completed = False
with open(os.path.join(outdir, "coverage.log"), "a") as coveragelog:
ret = self._generate(outdir, coveragelog)
if ret == 0:
report_log = {
"html": "HTML report generated: {}".format(os.path.join(outdir, "coverage", "index.html")),
"lcov": "LCOV report generated: {}".format(os.path.join(outdir, "coverage.info")),
"xml": "XML report generated: {}".format(os.path.join(outdir, "coverage", "coverage.xml")),
"csv": "CSV report generated: {}".format(os.path.join(outdir, "coverage", "coverage.csv")),
"txt": "TXT report generated: {}".format(os.path.join(outdir, "coverage", "coverage.txt")),
"coveralls": "Coveralls report generated: {}".format(os.path.join(outdir, "coverage", "coverage.coveralls.json")),
"sonarqube": "Sonarqube report generated: {}".format(os.path.join(outdir, "coverage", "coverage.sonarqube.xml"))
"html": "HTML report generated: {}".format(
os.path.join(outdir, "coverage", "index.html")
),
"lcov": "LCOV report generated: {}".format(
os.path.join(outdir, "coverage.info")
),
"xml": "XML report generated: {}".format(
os.path.join(outdir, "coverage", "coverage.xml")
),
"csv": "CSV report generated: {}".format(
os.path.join(outdir, "coverage", "coverage.csv")
),
"txt": "TXT report generated: {}".format(
os.path.join(outdir, "coverage", "coverage.txt")
),
"coveralls": "Coveralls report generated: {}".format(
os.path.join(outdir, "coverage", "coverage.coveralls.json")
),
"sonarqube": "Sonarqube report generated: {}".format(
os.path.join(outdir, "coverage", "coverage.sonarqube.xml")
)
}
for r in self.output_formats.split(','):
logger.info(report_log[r])
else:
coverage_completed = False
logger.debug("All coverage data processed: {}".format(coverage_completed))
logger.debug(f"All coverage data processed: {coverage_completed}")
return coverage_completed

View file

@ -286,8 +286,7 @@ Artificially long but functional example:
# Start of individual args place them in alpha-beta order
board_root_list = ["%s/boards" % ZEPHYR_BASE,
"%s/subsys/testsuite/boards" % ZEPHYR_BASE]
board_root_list = [f"{ZEPHYR_BASE}/boards", f"{ZEPHYR_BASE}/subsys/testsuite/boards"]
modules = zephyr_module.parse_modules(ZEPHYR_BASE)
for module in modules:
@ -934,10 +933,10 @@ def parse_arguments(parser: argparse.ArgumentParser, args, options = None, on_in
double_dash = len(options.extra_test_args)
unrecognized = " ".join(options.extra_test_args[0:double_dash])
logger.error("Unrecognized arguments found: '%s'. Use -- to "
"delineate extra arguments for test binary or pass "
"-h for help.",
unrecognized)
logger.error(
f"Unrecognized arguments found: '{unrecognized}'."
" Use -- to delineate extra arguments for test binary or pass -h for help."
)
sys.exit(1)
@ -1065,7 +1064,7 @@ class TwisterEnv:
args = []
script = os.fspath(args[0])
logger.debug("Running cmake script %s", script)
logger.debug(f"Running cmake script {script}")
cmake_args = ["-D{}".format(a.replace('"', '')) for a in args[1:]]
cmake_args.extend(['-P', script])
@ -1093,12 +1092,12 @@ class TwisterEnv:
out = strip_ansi_sequences(out.decode())
if p.returncode == 0:
msg = "Finished running %s" % (args[0])
msg = f"Finished running {args[0]}"
logger.debug(msg)
results = {"returncode": p.returncode, "msg": msg, "stdout": out}
else:
logger.error("CMake script failure: %s" % (args[0]))
logger.error(f"CMake script failure: {args[0]}")
results = {"returncode": p.returncode, "returnmsg": out}
return results

View file

@ -138,9 +138,10 @@ class Handler:
for tc in self.instance.testcases:
tc.status = TwisterStatus.FAIL
self.instance.reason = "Testsuite mismatch"
logger.debug("Test suite names were not printed or some of them in " \
"output do not correspond with expected: %s",
str(expected_suite_names))
logger.debug(
"Test suite names were not printed or some of them in output"
f" do not correspond with expected: {str(expected_suite_names)}",
)
def _final_handle_actions(self, harness, handler_time):
@ -166,7 +167,7 @@ class Handler:
# have added any additional images to the run target manually
domain_path = os.path.join(self.build_dir, "domains.yaml")
domains = Domains.from_file(domain_path)
logger.debug("Loaded sysbuild domain data from %s" % domain_path)
logger.debug(f"Loaded sysbuild domain data from {domain_path}")
build_dir = domains.get_default_domain().build_dir
else:
build_dir = self.build_dir
@ -217,7 +218,7 @@ class BinaryHandler(Handler):
stripped_line = line_decoded.rstrip()
if stripped_line.endswith(suffix):
stripped_line = stripped_line[:-len(suffix)].rstrip()
logger.debug("OUTPUT: %s", stripped_line)
logger.debug(f"OUTPUT: {stripped_line}")
log_out_fp.write(strip_ansi_sequences(line_decoded))
log_out_fp.flush()
harness.handle(stripped_line)
@ -343,10 +344,10 @@ class BinaryHandler(Handler):
harness.run_robot_test(command, self)
return
stderr_log = "{}/handler_stderr.log".format(self.instance.build_dir)
stderr_log = f"{self.instance.build_dir}/handler_stderr.log"
with open(stderr_log, "w+") as stderr_log_fp, subprocess.Popen(command, stdout=subprocess.PIPE,
stderr=stderr_log_fp, cwd=self.build_dir, env=env) as proc:
logger.debug("Spawning BinaryHandler Thread for %s" % self.name)
logger.debug(f"Spawning BinaryHandler Thread for {self.name}")
t = threading.Thread(target=self._output_handler, args=(proc, harness,), daemon=True)
t.start()
t.join()
@ -357,7 +358,7 @@ class BinaryHandler(Handler):
self.returncode = proc.returncode
if proc.returncode != 0:
self.instance.status = TwisterStatus.ERROR
self.instance.reason = "BinaryHandler returned {}".format(proc.returncode)
self.instance.reason = f"BinaryHandler returned {proc.returncode}"
self.try_kill_process_by_pid()
handler_time = time.time() - start_time
@ -521,7 +522,7 @@ class DeviceHandler(Handler):
except subprocess.TimeoutExpired:
proc.kill()
proc.communicate()
logger.error("{} timed out".format(script))
logger.error(f"{script} timed out")
def _create_command(self, runner, hardware):
if (self.options.west_flash is not None) or runner:
@ -550,13 +551,13 @@ class DeviceHandler(Handler):
command_extra_args.append(board_id)
elif runner == "openocd" and product == "STM32 STLink" or runner == "openocd" and product == "STLINK-V3":
command_extra_args.append("--cmd-pre-init")
command_extra_args.append("hla_serial %s" % board_id)
command_extra_args.append(f"hla_serial {board_id}")
elif runner == "openocd" and product == "EDBG CMSIS-DAP":
command_extra_args.append("--cmd-pre-init")
command_extra_args.append("cmsis_dap_serial %s" % board_id)
command_extra_args.append(f"cmsis_dap_serial {board_id}")
elif runner == "openocd" and product == "LPC-LINK2 CMSIS-DAP":
command_extra_args.append("--cmd-pre-init")
command_extra_args.append("adapter serial %s" % board_id)
command_extra_args.append(f"adapter serial {board_id}")
elif runner == "jlink":
command.append("--dev-id")
command.append(board_id)
@ -564,9 +565,9 @@ class DeviceHandler(Handler):
# for linkserver
# --probe=#<number> select by probe index
# --probe=<serial number> select by probe serial number
command.append("--probe=%s" % board_id)
command.append(f"--probe={board_id}")
elif runner == "stm32cubeprogrammer":
command.append("--tool-opt=sn=%s" % board_id)
command.append(f"--tool-opt=sn={board_id}")
# Receive parameters from runner_params field.
if hardware.runner_params:
@ -627,7 +628,7 @@ class DeviceHandler(Handler):
def _handle_serial_exception(self, exception, dut, serial_pty, ser_pty_process):
self.instance.status = TwisterStatus.FAIL
self.instance.reason = "Serial Device Error"
logger.error("Serial device error: %s" % (str(exception)))
logger.error(f"Serial device error: {exception!s}")
self.instance.add_missing_case_status(TwisterStatus.BLOCK, "Serial Device Error")
if serial_pty and ser_pty_process:
@ -666,10 +667,7 @@ class DeviceHandler(Handler):
)
except subprocess.CalledProcessError as error:
logger.error(
"Failed to run subprocess {}, error {}".format(
serial_pty,
error.output
)
f"Failed to run subprocess {serial_pty}, error {error.output}"
)
return
@ -734,8 +732,8 @@ class DeviceHandler(Handler):
start_time = time.time()
t.start()
d_log = "{}/device.log".format(self.instance.build_dir)
logger.debug('Flash command: %s', command)
d_log = f"{self.instance.build_dir}/device.log"
logger.debug(f'Flash command: {command}', )
flash_error = False
try:
stdout = stderr = None
@ -797,7 +795,7 @@ class DeviceHandler(Handler):
t.join(0.1)
if t.is_alive():
logger.debug("Timed out while monitoring serial output on {}".format(self.instance.platform.name))
logger.debug(f"Timed out while monitoring serial output on {self.instance.platform.name}")
if ser.isOpen():
ser.close()
@ -1036,7 +1034,7 @@ class QEMUHandler(Handler):
self.instance.reason = "Timeout"
else:
if not self.instance.reason:
self.instance.reason = "Exited with {}".format(self.returncode)
self.instance.reason = f"Exited with {self.returncode}"
self.instance.add_missing_case_status(TwisterStatus.BLOCK)
def handle(self, harness):
@ -1055,19 +1053,19 @@ class QEMUHandler(Handler):
self.ignore_unexpected_eof))
self.thread.daemon = True
logger.debug("Spawning QEMUHandler Thread for %s" % self.name)
logger.debug(f"Spawning QEMUHandler Thread for {self.name}")
self.thread.start()
thread_max_time = time.time() + self.get_test_timeout()
if sys.stdout.isatty():
subprocess.call(["stty", "sane"], stdin=sys.stdout)
logger.debug("Running %s (%s)" % (self.name, self.type_str))
logger.debug(f"Running {self.name} ({self.type_str})")
is_timeout = False
qemu_pid = None
with subprocess.Popen(command, stdout=open(self.stdout_fn, "w"), stderr=open(self.stderr_fn, "w"), cwd=self.build_dir) as proc:
logger.debug("Spawning QEMUHandler Thread for %s" % self.name)
logger.debug(f"Spawning QEMUHandler Thread for {self.name}")
try:
proc.wait(self.get_test_timeout())
@ -1205,7 +1203,7 @@ class QEMUWinHandler(Handler):
self.instance.reason = "Timeout"
else:
if not self.instance.reason:
self.instance.reason = "Exited with {}".format(self.returncode)
self.instance.reason = f"Exited with {self.returncode}"
self.instance.add_missing_case_status(TwisterStatus.BLOCK)
def _enqueue_char(self, queue):
@ -1333,14 +1331,14 @@ class QEMUWinHandler(Handler):
command = self._create_command(domain_build_dir)
self._set_qemu_filenames(domain_build_dir)
logger.debug("Running %s (%s)" % (self.name, self.type_str))
logger.debug(f"Running {self.name} ({self.type_str})")
is_timeout = False
self.stop_thread = False
queue = Queue()
with subprocess.Popen(command, stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT,
cwd=self.build_dir) as proc:
logger.debug("Spawning QEMUHandler Thread for %s" % self.name)
logger.debug(f"Spawning QEMUHandler Thread for {self.name}")
self.thread = threading.Thread(target=self._enqueue_char, args=(queue,))
self.thread.daemon = True

View file

@ -361,7 +361,7 @@ class HardwareMap:
s_dev.lock = None
self.detected.append(s_dev)
else:
logger.warning("Unsupported device (%s): %s" % (d.manufacturer, d))
logger.warning(f"Unsupported device ({d.manufacturer}): {d}")
def save(self, hwm_file):
# use existing map

View file

@ -222,8 +222,9 @@ class Robot(Harness):
# please note that there should be only one testcase in testcases list
self.instance.testcases[0].status = TwisterStatus.PASS
else:
logger.error("Robot test failure: %s for %s" %
(handler.sourcedir, self.instance.platform.name))
logger.error(
f"Robot test failure: {handler.sourcedir} for {self.instance.platform.name}"
)
self.instance.status = TwisterStatus.FAIL
self.instance.testcases[0].status = TwisterStatus.FAIL
@ -530,7 +531,7 @@ class Pytest(Harness):
else:
cmd_append_python_path = ''
cmd_to_print = cmd_append_python_path + shlex.join(cmd)
logger.debug('Running pytest command: %s', cmd_to_print)
logger.debug(f'Running pytest command: {cmd_to_print}')
return cmd, env
@ -541,7 +542,7 @@ class Pytest(Harness):
if not line:
continue
self._output.append(line)
logger.debug('PYTEST: %s', line)
logger.debug(f'PYTEST: {line}')
self.parse_record(line)
proc.communicate()
@ -639,11 +640,11 @@ class Gtest(Harness):
# Assert that we don't already have a running test
assert (
self.tc is None
), "gTest error, {} didn't finish".format(self.tc)
), f"gTest error, {self.tc} didn't finish"
# Check that the instance doesn't exist yet (prevents re-running)
tc = self.instance.get_case_by_name(name)
assert tc is None, "gTest error, {} running twice".format(tc)
assert tc is None, f"gTest error, {tc} running twice"
# Create the test instance and set the context
tc = self.instance.get_case_or_create(name)
@ -674,7 +675,7 @@ class Gtest(Harness):
tc = self.instance.get_case_by_name(name)
assert (
tc is not None and tc == self.tc
), "gTest error, mismatched tests. Expected {} but got {}".format(self.tc, tc)
), f"gTest error, mismatched tests. Expected {self.tc} but got {tc}"
# Test finished, clear the context
self.tc = None
@ -743,13 +744,13 @@ class Test(Harness):
for ts_name_ in ts_names:
if self.started_suites[ts_name_]['count'] < (0 if phase == 'TS_SUM' else 1):
continue
tc_fq_id = "{}.{}.{}".format(self.id, ts_name_, tc_name)
tc_fq_id = f"{self.id}.{ts_name_}.{tc_name}"
if tc := self.instance.get_case_by_name(tc_fq_id):
if self.trace:
logger.debug(f"On {phase}: Ztest case '{tc_name}' matched to '{tc_fq_id}")
return tc
logger.debug(f"On {phase}: Ztest case '{tc_name}' is not known in {self.started_suites} running suite(s).")
tc_id = "{}.{}".format(self.id, tc_name)
tc_id = f"{self.id}.{tc_name}"
return self.instance.get_case_or_create(tc_id)
def start_suite(self, suite_name):

View file

@ -152,15 +152,17 @@ class GNUMakeJobClient(JobClient):
rc = fcntl.fcntl(pipe[0], fcntl.F_GETFL)
if rc & os.O_ACCMODE != os.O_RDONLY:
logger.warning(
"FD %s is not readable (flags=%x); "
"ignoring GNU make jobserver", pipe[0], rc)
f"FD {pipe[0]} is not readable (flags={rc:x});"
" ignoring GNU make jobserver"
)
pipe = None
if pipe:
rc = fcntl.fcntl(pipe[1], fcntl.F_GETFL)
if rc & os.O_ACCMODE != os.O_WRONLY:
logger.warning(
"FD %s is not writable (flags=%x); "
"ignoring GNU make jobserver", pipe[1], rc)
f"FD {pipe[1]} is not writable (flags={rc:x});"
" ignoring GNU make jobserver"
)
pipe = None
if pipe:
logger.info("using GNU make jobserver")

View file

@ -177,4 +177,4 @@ class Platform:
return next(iter(self.simulators), None)
def __repr__(self):
return "<%s on %s>" % (self.name, self.arch)
return f"<{self.name} on {self.arch}>"

View file

@ -38,7 +38,7 @@ class Quarantine:
def get_matched_quarantine(self, testname, platform, architecture, simulator):
qelem = self.quarantine.get_matched_quarantine(testname, platform, architecture, simulator)
if qelem:
logger.debug('%s quarantined with reason: %s' % (testname, qelem.comment))
logger.debug(f'{testname} quarantined with reason: {qelem.comment}')
return qelem.comment
return None

View file

@ -450,7 +450,7 @@ class Reporting:
("used_rom", int, True)]
if not os.path.exists(filename):
logger.error("Cannot compare metrics, %s not found" % filename)
logger.error(f"Cannot compare metrics, {filename} not found")
return []
results = []
@ -506,9 +506,7 @@ class Reporting:
if show_footprint:
logger.log(
logging.INFO if all_deltas else logging.WARNING,
"{:<25} {:<60} {} {:<+4}, is now {:6} {:+.2%}".format(
i.platform.name, i.testsuite.name,
metric, delta, value, percentage))
f"{i.platform.name:<25} {i.testsuite.name:<60} {metric} {delta:<+4}, is now {value:6} {percentage:+.2%}")
warnings += 1
@ -574,9 +572,11 @@ class Reporting:
if instance.status == TwisterStatus.FAIL:
failed += 1
elif not ignore_unrecognized_sections and instance.metrics.get("unrecognized"):
logger.error("%sFAILED%s: %s has unrecognized binary sections: %s" %
(Fore.RED, Fore.RESET, instance.name,
str(instance.metrics.get("unrecognized", []))))
logger.error(
f"{Fore.RED}FAILED{Fore.RESET}:"
f" {instance.name} has unrecognized binary sections:"
f" {instance.metrics.get('unrecognized', [])!s}"
)
failed += 1
# FIXME: need a better way to identify executed tests
@ -648,7 +648,7 @@ class Reporting:
filename = os.path.join(outdir, report_name)
if suffix:
filename = "{}_{}".format(filename, suffix)
filename = f"{filename}_{suffix}"
if not no_update:
json_file = filename + ".json"
@ -669,10 +669,10 @@ class Reporting:
platforms = {repr(inst.platform):inst.platform for _, inst in self.instances.items()}
for platform in platforms.values():
if suffix:
filename = os.path.join(outdir,"{}_{}.xml".format(platform.normalized_name, suffix))
json_platform_file = os.path.join(outdir,"{}_{}".format(platform.normalized_name, suffix))
filename = os.path.join(outdir,f"{platform.normalized_name}_{suffix}.xml")
json_platform_file = os.path.join(outdir,f"{platform.normalized_name}_{suffix}")
else:
filename = os.path.join(outdir,"{}.xml".format(platform.normalized_name))
filename = os.path.join(outdir,f"{platform.normalized_name}.xml")
json_platform_file = os.path.join(outdir, platform.normalized_name)
self.xunit_report(json_file, filename, platform.name, full_report=True)
self.json_report(json_platform_file + ".json",

View file

@ -181,7 +181,7 @@ class ExecutionCounter:
Node(f"Test cases only started: {self.started_cases}", parent=error_cases_node)
for pre, _, node in RenderTree(root):
print("%s%s" % (pre, node.name))
print(f"{pre}{node.name}")
@property
def warnings(self):
@ -521,7 +521,7 @@ class CMake:
if args is None:
args = []
logger.debug("Building %s for %s" % (self.source_dir, self.platform.name))
logger.debug(f"Building {self.source_dir} for {self.platform.name}")
cmake_args = []
cmake_args.extend(args)
@ -578,9 +578,9 @@ class CMake:
overflow_found = re.findall("region `(FLASH|ROM|RAM|ICCM|DCCM|SRAM|dram\\d_\\d_seg)' overflowed by", log_msg)
imgtool_overflow_found = re.findall(r"Error: Image size \(.*\) \+ trailer \(.*\) exceeds requested size", log_msg)
if overflow_found and not self.options.overflow_as_errors:
logger.debug("Test skipped due to {} Overflow".format(overflow_found[0]))
logger.debug(f"Test skipped due to {overflow_found[0]} Overflow")
self.instance.status = TwisterStatus.SKIP
self.instance.reason = "{} overflow".format(overflow_found[0])
self.instance.reason = f"{overflow_found[0]} overflow"
change_skip_to_error_if_integration(self.options, self.instance)
elif imgtool_overflow_found and not self.options.overflow_as_errors:
self.instance.status = TwisterStatus.SKIP
@ -611,7 +611,7 @@ class CMake:
if self.instance.sysbuild:
warning_command = 'SB_' + warning_command
logger.debug("Running cmake on %s for %s" % (self.source_dir, self.platform.name))
logger.debug(f"Running cmake on {self.source_dir} for {self.platform.name}")
cmake_args = [
f'-B{self.build_dir}',
f'-DTC_RUNID={self.instance.run_id}',
@ -633,7 +633,7 @@ class CMake:
]
if self.instance.sysbuild and not filter_stages:
logger.debug("Building %s using sysbuild" % (self.source_dir))
logger.debug(f"Building {self.source_dir} using sysbuild")
source_args = [
f'-S{canonical_zephyr_base}/share/sysbuild',
f'-DAPP_DIR={self.source_dir}'
@ -646,7 +646,7 @@ class CMake:
cmake_args.extend(args)
cmake_opts = ['-DBOARD={}'.format(self.platform.name)]
cmake_opts = [f'-DBOARD={self.platform.name}']
cmake_args.extend(cmake_opts)
if self.instance.testsuite.required_snippets:
@ -696,7 +696,7 @@ class CMake:
for tc in self.instance.testcases:
tc.status = self.instance.status
logger.error("CMake build failure: %s for %s" % (self.source_dir, self.platform.name))
logger.error(f"CMake build failure: {self.source_dir} for {self.platform.name}")
ret = {"returncode": p.returncode}
if out:
@ -726,7 +726,7 @@ class FilterBuilder(CMake):
# Load domain yaml to get default domain build directory
domain_path = os.path.join(self.build_dir, "domains.yaml")
domains = Domains.from_file(domain_path)
logger.debug("Loaded sysbuild domain data from %s" % (domain_path))
logger.debug(f"Loaded sysbuild domain data from {domain_path}")
self.instance.domains = domains
domain_build = domains.get_default_domain().build_dir
cmake_cache_path = os.path.join(domain_build, "CMakeCache.txt")
@ -749,7 +749,7 @@ class FilterBuilder(CMake):
m = self.config_re.match(line)
if not m:
if line.strip() and not line.startswith("#"):
sys.stderr.write("Unrecognized line %s\n" % line)
sys.stderr.write(f"Unrecognized line {line}\n")
continue
defconfig[m.group(1)] = m.group(2).strip()
@ -796,8 +796,7 @@ class FilterBuilder(CMake):
ret = expr_parser.parse(self.testsuite.filter, filter_data, edt)
except (ValueError, SyntaxError) as se:
sys.stderr.write(
"Failed processing %s\n" % self.testsuite.yamlfile)
sys.stderr.write(f"Failed processing {self.testsuite.yamlfile}\n")
raise se
if not ret:
@ -828,13 +827,13 @@ class ProjectBuilder(FilterBuilder):
def log_info(self, filename, inline_logs, log_testcases=False):
filename = os.path.abspath(os.path.realpath(filename))
if inline_logs:
logger.info("{:-^100}".format(filename))
logger.info(f"{filename:-^100}")
try:
with open(filename) as fp:
data = fp.read()
except Exception as e:
data = "Unable to read log data (%s)\n" % (str(e))
data = f"Unable to read log data ({e!s})\n"
# Remove any coverage data from the dumped logs
data = re.sub(
@ -845,7 +844,7 @@ class ProjectBuilder(FilterBuilder):
)
logger.error(data)
logger.info("{:-^100}".format(filename))
logger.info(f"{filename:-^100}")
if log_testcases:
for tc in self.instance.testcases:
@ -862,25 +861,25 @@ class ProjectBuilder(FilterBuilder):
def log_info_file(self, inline_logs):
build_dir = self.instance.build_dir
h_log = "{}/handler.log".format(build_dir)
he_log = "{}/handler_stderr.log".format(build_dir)
b_log = "{}/build.log".format(build_dir)
v_log = "{}/valgrind.log".format(build_dir)
d_log = "{}/device.log".format(build_dir)
pytest_log = "{}/twister_harness.log".format(build_dir)
h_log = f"{build_dir}/handler.log"
he_log = f"{build_dir}/handler_stderr.log"
b_log = f"{build_dir}/build.log"
v_log = f"{build_dir}/valgrind.log"
d_log = f"{build_dir}/device.log"
pytest_log = f"{build_dir}/twister_harness.log"
if os.path.exists(v_log) and "Valgrind" in self.instance.reason:
self.log_info("{}".format(v_log), inline_logs)
self.log_info(f"{v_log}", inline_logs)
elif os.path.exists(pytest_log) and os.path.getsize(pytest_log) > 0:
self.log_info("{}".format(pytest_log), inline_logs, log_testcases=True)
self.log_info(f"{pytest_log}", inline_logs, log_testcases=True)
elif os.path.exists(h_log) and os.path.getsize(h_log) > 0:
self.log_info("{}".format(h_log), inline_logs)
self.log_info(f"{h_log}", inline_logs)
elif os.path.exists(he_log) and os.path.getsize(he_log) > 0:
self.log_info("{}".format(he_log), inline_logs)
self.log_info(f"{he_log}", inline_logs)
elif os.path.exists(d_log) and os.path.getsize(d_log) > 0:
self.log_info("{}".format(d_log), inline_logs)
self.log_info(f"{d_log}", inline_logs)
else:
self.log_info("{}".format(b_log), inline_logs)
self.log_info(f"{b_log}", inline_logs)
def _add_to_pipeline(self, pipeline, op: str, additionals: dict=None):
@ -913,7 +912,7 @@ class ProjectBuilder(FilterBuilder):
else:
# Here we check the dt/kconfig filter results coming from running cmake
if self.instance.name in ret['filter'] and ret['filter'][self.instance.name]:
logger.debug("filtering %s" % self.instance.name)
logger.debug(f"filtering {self.instance.name}")
self.instance.status = TwisterStatus.FILTER
self.instance.reason = "runtime filter"
results.filtered_runtime_increment()
@ -939,14 +938,14 @@ class ProjectBuilder(FilterBuilder):
next_op = 'report'
elif self.options.cmake_only:
if self.instance.status == TwisterStatus.NONE:
logger.debug("CMake only: PASS %s" % self.instance.name)
logger.debug(f"CMake only: PASS {self.instance.name}")
self.instance.status = TwisterStatus.NOTRUN
self.instance.add_missing_case_status(TwisterStatus.NOTRUN, 'CMake only')
next_op = 'report'
else:
# Here we check the runtime filter results coming from running cmake
if self.instance.name in ret['filter'] and ret['filter'][self.instance.name]:
logger.debug("filtering %s" % self.instance.name)
logger.debug(f"filtering {self.instance.name}")
self.instance.status = TwisterStatus.FILTER
self.instance.reason = "runtime filter"
results.filtered_runtime_increment()
@ -966,7 +965,7 @@ class ProjectBuilder(FilterBuilder):
elif op == "build":
try:
logger.debug("build test: %s" % self.instance.name)
logger.debug(f"build test: {self.instance.name}")
ret = self.build()
if not ret:
self.instance.status = TwisterStatus.ERROR
@ -1033,7 +1032,7 @@ class ProjectBuilder(FilterBuilder):
# Run the generated binary using one of the supported handlers
elif op == "run":
try:
logger.debug("run test: %s" % self.instance.name)
logger.debug(f"run test: {self.instance.name}")
self.run()
logger.debug(f"run status: {self.instance.name} {self.instance.status}")
@ -1176,7 +1175,7 @@ class ProjectBuilder(FilterBuilder):
def cleanup_artifacts(self, additional_keep: list[str] = None):
if additional_keep is None:
additional_keep = []
logger.debug("Cleaning up {}".format(self.instance.build_dir))
logger.debug(f"Cleaning up {self.instance.build_dir}")
allow = [
os.path.join('zephyr', '.config'),
'handler.log',
@ -1214,7 +1213,7 @@ class ProjectBuilder(FilterBuilder):
os.rmdir(path)
def cleanup_device_testing_artifacts(self):
logger.debug("Cleaning up for Device Testing {}".format(self.instance.build_dir))
logger.debug(f"Cleaning up for Device Testing {self.instance.build_dir}")
files_to_keep = self._get_binaries()
files_to_keep.append(os.path.join('zephyr', 'runners.yaml'))
@ -1427,11 +1426,7 @@ class ProjectBuilder(FilterBuilder):
status += " " + instance.reason
else:
logger.error(
"{:<25} {:<50} {}: {}".format(
instance.platform.name,
instance.testsuite.name,
status,
instance.reason))
f"{instance.platform.name:<25} {instance.testsuite.name:<50} {status}: {instance.reason}")
if not self.options.verbose:
self.log_info_file(self.options.inline_logs)
elif instance.status == TwisterStatus.SKIP:
@ -1458,7 +1453,7 @@ class ProjectBuilder(FilterBuilder):
if instance.dut:
more_info += f": {instance.dut},"
if htime:
more_info += " {:.3f}s".format(htime)
more_info += f" {htime:.3f}s"
else:
more_info = "build"
@ -1466,9 +1461,11 @@ class ProjectBuilder(FilterBuilder):
and hasattr(self.instance.handler, 'seed')
and self.instance.handler.seed is not None ):
more_info += "/seed: " + str(self.options.seed)
logger.info("{:>{}}/{} {:<25} {:<50} {} ({})".format(
results.done - results.filtered_static, total_tests_width, total_to_do , instance.platform.name,
instance.testsuite.name, status, more_info))
logger.info(
f"{results.done - results.filtered_static:>{total_tests_width}}/{total_to_do}"
f" {instance.platform.name:<25} {instance.testsuite.name:<50}"
f" {status} ({more_info})"
)
if self.options.verbose > 1:
for tc in self.instance.testcases:
@ -1484,26 +1481,33 @@ class ProjectBuilder(FilterBuilder):
if total_to_do > 0:
completed_perc = int((float(results.done - results.filtered_static) / total_to_do) * 100)
sys.stdout.write("INFO - Total complete: %s%4d/%4d%s %2d%% built (not run): %s%4d%s, filtered: %s%4d%s, failed: %s%4d%s, error: %s%4d%s\r" % (
TwisterStatus.get_color(TwisterStatus.PASS),
results.done - results.filtered_static,
total_to_do,
Fore.RESET,
completed_perc,
TwisterStatus.get_color(TwisterStatus.NOTRUN),
results.notrun,
Fore.RESET,
TwisterStatus.get_color(TwisterStatus.SKIP) if results.filtered_configs > 0 else Fore.RESET,
results.filtered_configs,
Fore.RESET,
TwisterStatus.get_color(TwisterStatus.FAIL) if results.failed > 0 else Fore.RESET,
results.failed,
Fore.RESET,
TwisterStatus.get_color(TwisterStatus.ERROR) if results.error > 0 else Fore.RESET,
results.error,
Fore.RESET
)
)
unfiltered = results.done - results.filtered_static
filtered_section_color = (
TwisterStatus.get_color(TwisterStatus.SKIP)
if results.filtered_configs > 0
else Fore.RESET
)
failed_section_color = (
TwisterStatus.get_color(TwisterStatus.FAIL) if results.failed > 0 else Fore.RESET
)
error_section_color = (
TwisterStatus.get_color(TwisterStatus.ERROR) if results.error > 0 else Fore.RESET
)
sys.stdout.write(
f"INFO - Total complete: "
f"{TwisterStatus.get_color(TwisterStatus.PASS)}"
f"{unfiltered:>4}/{total_to_do:>4}"
f"{Fore.RESET} {completed_perc:>2}%"
" built (not run):"
f" {TwisterStatus.get_color(TwisterStatus.NOTRUN)}{results.notrun:>4}{Fore.RESET},"
" filtered:"
f" {filtered_section_color}{results.filtered_configs:>4}{Fore.RESET},"
" failed:"
f" {failed_section_color}{results.failed:>4}{Fore.RESET},"
" error:"
f" {error_section_color}{results.error:>4}{Fore.RESET}\r"
)
sys.stdout.flush()
@staticmethod
@ -1535,7 +1539,7 @@ class ProjectBuilder(FilterBuilder):
overlays.append(additional_overlay_path)
if overlays:
args.append("OVERLAY_CONFIG=\"%s\"" % (" ".join(overlays)))
args.append(f"OVERLAY_CONFIG=\"{' '.join(overlays)}\"")
# Build the final argument list
args_expanded.extend(["-D{}".format(a.replace('"', '\"')) for a in cmake_extra_args])
@ -1703,7 +1707,7 @@ class TwisterRunner:
else:
self.jobserver = JobClient()
logger.info("JOBS: %d", self.jobs)
logger.info(f"JOBS: {self.jobs}")
self.update_counting_before_pipeline()
@ -1711,7 +1715,7 @@ class TwisterRunner:
self.results.iteration_increment()
if self.results.iteration > 1:
logger.info("%d Iteration:" % (self.results.iteration))
logger.info(f"{self.results.iteration} Iteration:")
time.sleep(self.options.retry_interval) # waiting for the system to settle down
self.results.done = self.results.total - self.results.failed
self.results.failed = 0
@ -1762,12 +1766,12 @@ class TwisterRunner:
self.results.error_increment()
def show_brief(self):
logger.info("%d test scenarios (%d configurations) selected, "
"%d configurations filtered (%d by static filter, %d at runtime)." %
(len(self.suites), len(self.instances),
self.results.filtered_configs,
self.results.filtered_static,
self.results.filtered_configs - self.results.filtered_static))
logger.info(
f"{len(self.suites)} test scenarios ({len(self.instances)} configurations) selected,"
f" {self.results.filtered_configs} configurations filtered"
f" ({self.results.filtered_static} by static filter,"
f" {self.results.filtered_configs - self.results.filtered_static} at runtime)."
)
def add_tasks_to_queue(self, pipeline, build_only=False, test_only=False, retry_build_errors=False):
for instance in self.instances.values():

View file

@ -132,12 +132,12 @@ class SizeCalculator:
print(self.elf_filename)
print("SECTION NAME VMA LMA SIZE HEX SZ TYPE")
for v in self.sections:
print("%-17s 0x%08x 0x%08x %8d 0x%05x %-7s" %
(v["name"], v["virt_addr"], v["load_addr"], v["size"], v["size"],
v["type"]))
print(
f'{v["name"]:<17} {v["virt_addr"]:#010x} {v["load_addr"]:#010x}'
f' {v["size"]:>8} {v["size"]:#07x} {v["type"]:<7}'
)
print("Totals: %d bytes (ROM), %d bytes (RAM)" %
(self.used_rom, self.used_ram))
print(f"Totals: {self.used_rom} bytes (ROM), {self.used_ram} bytes (RAM)")
print("")
def get_used_ram(self):
@ -196,7 +196,7 @@ class SizeCalculator:
try:
if magic != b'\x7fELF':
raise TwisterRuntimeError("%s is not an ELF binary" % self.elf_filename)
raise TwisterRuntimeError(f"{self.elf_filename} is not an ELF binary")
except Exception as e:
print(str(e))
sys.exit(2)
@ -212,7 +212,7 @@ class SizeCalculator:
"utf-8").strip()
try:
if is_xip_output.endswith("no symbols"):
raise TwisterRuntimeError("%s has no symbol information" % self.elf_filename)
raise TwisterRuntimeError(f"{self.elf_filename} has no symbol information")
except Exception as e:
print(str(e))
sys.exit(2)

View file

@ -397,4 +397,4 @@ class TestInstance:
return buildlog_paths[0]
def __repr__(self):
return "<TestSuite %s on %s>" % (self.testsuite.name, self.platform.name)
return f"<TestSuite {self.testsuite.name} on {self.platform.name}>"

View file

@ -175,7 +175,7 @@ class TestPlan:
if self.run_individual_testsuite:
logger.info("Running the following tests:")
for test in self.run_individual_testsuite:
print(" - {}".format(test))
print(f" - {test}")
else:
raise TwisterRuntimeError("Tests not found")
@ -217,7 +217,7 @@ class TestPlan:
def load(self):
if self.options.report_suffix:
last_run = os.path.join(self.options.outdir, "twister_{}.json".format(self.options.report_suffix))
last_run = os.path.join(self.options.outdir, f"twister_{self.options.report_suffix}.json")
else:
last_run = os.path.join(self.options.outdir, "twister.json")
@ -262,7 +262,7 @@ class TestPlan:
raise TwisterRuntimeError("subset should not exceed the total number of sets")
if int(subset) > 0 and int(sets) >= int(subset):
logger.info("Running only a subset: %s/%s" % (subset, sets))
logger.info(f"Running only a subset: {subset}/{sets}")
else:
raise TwisterRuntimeError(f"You have provided a wrong subset value: {self.options.subset}.")
@ -347,9 +347,9 @@ class TestPlan:
if dupes:
msg = "Duplicated test scenarios found:\n"
for dupe in dupes:
msg += ("- {} found in:\n".format(dupe))
msg += (f"- {dupe} found in:\n")
for dc in self.get_testsuite(dupe):
msg += (" - {}\n".format(dc.yamlfile))
msg += (f" - {dc.yamlfile}\n")
raise TwisterRuntimeError(msg)
else:
logger.debug("No duplicates found.")
@ -360,7 +360,7 @@ class TestPlan:
tags = tags.union(tc.tags)
for t in tags:
print("- {}".format(t))
print(f"- {t}")
def report_test_tree(self):
tests_list = self.get_tests_list()
@ -399,7 +399,7 @@ class TestPlan:
Node(test, parent=subarea)
for pre, _, node in RenderTree(testsuite):
print("%s%s" % (pre, node.name))
print(f"{pre}{node.name}")
def report_test_list(self):
tests_list = self.get_tests_list()
@ -407,8 +407,8 @@ class TestPlan:
cnt = 0
for test in sorted(tests_list):
cnt = cnt + 1
print(" - {}".format(test))
print("{} total.".format(cnt))
print(f" - {test}")
print(f"{cnt} total.")
# Debug Functions
@ -550,7 +550,7 @@ class TestPlan:
for root in self.env.test_roots:
root = os.path.abspath(root)
logger.debug("Reading test case configuration files under %s..." % root)
logger.debug(f"Reading test case configuration files under {root}...")
for dirpath, _, filenames in os.walk(root, topdown=True):
if self.SAMPLE_FILENAME in filenames:
@ -570,8 +570,9 @@ class TestPlan:
os.path.relpath(suite_path, root),
filename)
if os.path.exists(alt_config):
logger.info("Using alternative configuration from %s" %
os.path.normpath(alt_config))
logger.info(
f"Using alternative configuration from {os.path.normpath(alt_config)}"
)
suite_yaml_path = alt_config
break
@ -981,7 +982,9 @@ class TestPlan:
# Search and check that all required snippet files are found
for this_snippet in snippet_args['snippets']:
if this_snippet not in found_snippets:
logger.error("Can't find snippet '%s' for test '%s'", this_snippet, ts.name)
logger.error(
f"Can't find snippet '{this_snippet}' for test '{ts.name}'"
)
instance.status = TwisterStatus.ERROR
instance.reason = f"Snippet {this_snippet} not found"
missing_snippet = True

View file

@ -301,9 +301,8 @@ def scan_testsuite_path(testsuite_path):
try:
result: ScanPathResult = scan_file(filename)
if result.warnings:
logger.error("%s: %s" % (filename, result.warnings))
raise TwisterRuntimeError(
"%s: %s" % (filename, result.warnings))
logger.error(f"{filename}: {result.warnings}")
raise TwisterRuntimeError(f"{filename}: {result.warnings}")
if result.matches:
subcases += result.matches
if result.has_registered_test_suites:
@ -316,7 +315,7 @@ def scan_testsuite_path(testsuite_path):
ztest_suite_names += result.ztest_suite_names
except ValueError as e:
logger.error("%s: error parsing source file: %s" % (filename, e))
logger.error(f"{filename}: error parsing source file: {e}")
src_dir_pathlib_path = Path(src_dir_path)
for filename in find_c_files_in(testsuite_path):
@ -328,13 +327,13 @@ def scan_testsuite_path(testsuite_path):
try:
result: ScanPathResult = scan_file(filename)
if result.warnings:
logger.error("%s: %s" % (filename, result.warnings))
logger.error(f"{filename}: {result.warnings}")
if result.matches:
subcases += result.matches
if result.ztest_suite_names:
ztest_suite_names += result.ztest_suite_names
except ValueError as e:
logger.error("%s: can't find: %s" % (filename, e))
logger.error(f"{filename}: can't find: {e}")
if (has_registered_test_suites and has_test_main and
not has_run_registered_test_suites):
@ -388,7 +387,7 @@ class TestCase(DisablePyTestCollectionMixin):
return self.name < other.name
def __repr__(self):
return "<TestCase %s with %s>" % (self.name, self.status)
return f"<TestCase {self.name} with {self.status}>"
def __str__(self):
return self.name
@ -469,7 +468,7 @@ class TestSuite(DisablePyTestCollectionMixin):
else:
# only add each testcase once
for sub in set(parsed_subcases):
name = "{}.{}".format(self.id, sub)
name = f"{self.id}.{sub}"
self.add_testcase(name)
if suite_names:

View file

@ -82,13 +82,13 @@ def main(options: argparse.Namespace, default_options: argparse.Namespace):
sys.exit(f"Can't compare metrics with non existing file {ls}")
elif os.path.exists(options.outdir):
if options.clobber_output:
print("Deleting output directory {}".format(options.outdir))
print(f"Deleting output directory {options.outdir}")
shutil.rmtree(options.outdir)
else:
for i in range(1, 100):
new_out = options.outdir + ".{}".format(i)
new_out = options.outdir + f".{i}"
if not os.path.exists(new_out):
print("Renaming output directory to {}".format(new_out))
print(f"Renaming output directory to {new_out}")
shutil.move(options.outdir, new_out)
break
else:
@ -141,13 +141,7 @@ def main(options: argparse.Namespace, default_options: argparse.Namespace):
if options.platform and not tplan.check_platform(i.platform, options.platform):
continue
logger.debug(
"{:<25} {:<50} {}SKIPPED{}: {}".format(
i.platform.name,
i.testsuite.name,
Fore.YELLOW,
Fore.RESET,
i.reason,
)
f"{i.platform.name:<25} {i.testsuite.name:<50} {Fore.YELLOW}SKIPPED{Fore.RESET}: {i.reason}"
)
report = Reporting(tplan, env)
@ -173,7 +167,7 @@ def main(options: argparse.Namespace, default_options: argparse.Namespace):
if options.dry_run:
duration = time.time() - start_time
logger.info("Completed in %d seconds" % (duration))
logger.info(f"Completed in {duration} seconds")
return 0
if options.short_build_path: