Modernize python and update pylint (#5096)

Update code to conform to the newer version of pylint available in
ubuntu-22.04, with few exceptions:
    - disabled `import-outside-toplevel` for `main()` in
      `jerry_client.py`
    - disabled `consider-using-with` for the logfile of `TestSuite` in
      `test262-harness.py` as using `with` is not practical in that case

Update test262-harness.py to use argparse instead of the now deprecated
optparse

Rename variables in jerry_client_main.py that redefined python builtins
or shadowed variables from an outer scope

Update python files to use f-stirngs

Add minimum python versions (3.6 and 3.8) to the CI jobs: without it the
default python version did not support the `with` statement for
`subprocess.Popen` used in `build.py` on macos, or in some cases f-stirngs

Remove `from __future__` imports that are no-ops in python 3

Remove shebang from non executable files

Re-enable most pylint checkers, except `missing-docstring`

JerryScript-DCO-1.0-Signed-off-by: Máté Tokodi mate.tokodi@szteszoftver.hu
This commit is contained in:
Máté Tokodi
2023-10-25 17:32:14 +02:00
committed by GitHub
parent a588e49661
commit bc408b159b
26 changed files with 469 additions and 503 deletions
+30 -34
View File
@@ -14,7 +14,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import print_function
import argparse
import os
import re
@@ -78,7 +77,7 @@ def update_exclude_list(args):
passing_tests = set()
failing_tests = set()
new_passing_tests = set()
with open(os.path.join(os.path.dirname(args.engine), 'test262.report'), 'r') as report_file:
with open(os.path.join(os.path.dirname(args.engine), 'test262.report'), 'r', encoding='utf8') as report_file:
for line in report_file:
match = re.match('(=== )?(.*) (?:failed|passed) in (?:non-strict|strict)', line)
if match:
@@ -92,7 +91,7 @@ def update_exclude_list(args):
# Tests pass in strict-mode but fail in non-strict-mode (or vice versa) should be considered as failures
passing_tests = passing_tests - failing_tests
with open(args.excludelist_path, 'r+') as exclude_file:
with open(args.excludelist_path, 'r+', encoding='utf8') as exclude_file:
lines = exclude_file.readlines()
exclude_file.seek(0)
exclude_file.truncate()
@@ -167,41 +166,38 @@ def main(args):
if args.test262_test_list:
test262_command.extend(args.test262_test_list.split(','))
proc = subprocess.Popen(test262_command,
universal_newlines=True,
stdout=subprocess.PIPE,
**kwargs)
with subprocess.Popen(test262_command, universal_newlines=True, stdout=subprocess.PIPE, **kwargs) as proc:
return_code = 1
with open(os.path.join(os.path.dirname(args.engine), 'test262.report'), 'w') as output_file:
counter = 0
summary_found = False
summary_end_found = False
while True:
output = proc.stdout.readline()
if not output:
break
output_file.write(output)
return_code = 1
with open(os.path.join(os.path.dirname(args.engine), 'test262.report'), 'w', encoding='utf8') as output_file:
counter = 0
summary_found = False
summary_end_found = False
while True:
output = proc.stdout.readline()
if not output:
break
output_file.write(output)
if output.startswith('=== Summary ==='):
summary_found = True
print('')
if output.startswith('=== Summary ==='):
summary_found = True
print('')
if summary_found:
if not summary_end_found:
print(output, end='')
if not output.strip():
summary_end_found = True
if 'All tests succeeded' in output:
return_code = 0
elif re.search('in (non-)?strict mode', output):
counter += 1
if (counter % 100) == 0:
print(".", end='')
if (counter % 5000) == 0:
print(" Executed %d tests." % counter)
if summary_found:
if not summary_end_found:
print(output, end='')
if not output.strip():
summary_end_found = True
if 'All tests succeeded' in output:
return_code = 0
elif re.search('in (non-)?strict mode', output):
counter += 1
if (counter % 100) == 0:
print(".", end='')
if (counter % 5000) == 0:
print(f" Executed {counter} tests.")
proc.wait()
proc.wait()
if sys.platform == 'win32':
util.set_timezone(original_timezone)
+12 -13
View File
@@ -14,7 +14,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import print_function
import argparse
import os
import subprocess
@@ -22,7 +21,7 @@ import sys
import util
def get_arguments():
def get_args():
execution_runtime = os.environ.get('RUNTIME')
parser = argparse.ArgumentParser()
parser.add_argument('-q', '--quiet', action='store_true',
@@ -60,7 +59,7 @@ def get_tests(test_dir, test_list, skip_list):
if test_list:
dirname = os.path.dirname(test_list)
with open(test_list, "r") as test_list_fd:
with open(test_list, "r", encoding='utf8') as test_list_fd:
for test in test_list_fd:
tests.append(os.path.normpath(os.path.join(dirname, test.rstrip())))
@@ -79,10 +78,10 @@ def execute_test_command(test_cmd):
kwargs = {}
if sys.version_info.major >= 3:
kwargs['encoding'] = 'unicode_escape'
process = subprocess.Popen(test_cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
universal_newlines=True, **kwargs)
stdout = process.communicate()[0]
return (process.returncode, stdout)
with subprocess.Popen(test_cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
universal_newlines=True, **kwargs) as process:
stdout, _ = process.communicate()
return process.returncode, stdout
def main(args):
@@ -142,10 +141,10 @@ def run_normal_tests(args, tests):
if (returncode == 0 and not is_expected_to_fail) or (returncode == 1 and is_expected_to_fail):
passed += 1
if not args.quiet:
passed_string = 'PASS' + (' (XFAIL)' if is_expected_to_fail else '')
passed_string = f"PASS{' (XFAIL)' if is_expected_to_fail else ''}"
util.print_test_result(tested, total, True, passed_string, test_path)
else:
passed_string = 'FAIL%s (%d)' % (' (XPASS)' if returncode == 0 and is_expected_to_fail else '', returncode)
passed_string = f"FAIL{' (XPASS)' if returncode == 0 and is_expected_to_fail else ''} ({returncode})"
util.print_test_result(tested, total, False, passed_string, test_path)
print("================================================")
print(stdout)
@@ -183,7 +182,7 @@ def run_snapshot_tests(args, tests):
passed_string = 'PASS' + (' (XFAIL)' if returncode else '')
util.print_test_result(tested, total, True, passed_string, test_path, True)
else:
util.print_test_result(tested, total, False, 'FAIL (%d)' % (returncode), test_path, True)
util.print_test_result(tested, total, False, f'FAIL ({returncode})', test_path, True)
print("================================================")
print(stdout)
print("================================================")
@@ -199,10 +198,10 @@ def run_snapshot_tests(args, tests):
if (returncode == 0 and not is_expected_to_fail) or (returncode == 1 and is_expected_to_fail):
passed += 1
if not args.quiet:
passed_string = 'PASS' + (' (XFAIL)' if is_expected_to_fail else '')
passed_string = f"PASS{' (XFAIL)' if is_expected_to_fail else ''}"
util.print_test_result(tested, total, True, passed_string, test_path, False)
else:
passed_string = 'FAIL%s (%d)' % (' (XPASS)' if returncode == 0 and is_expected_to_fail else '', returncode)
passed_string = f"FAIL{' (XPASS)' if returncode == 0 and is_expected_to_fail else ''} ({returncode})"
util.print_test_result(tested, total, False, passed_string, test_path, False)
print("================================================")
print(stdout)
@@ -212,4 +211,4 @@ def run_snapshot_tests(args, tests):
if __name__ == "__main__":
sys.exit(main(get_arguments()))
sys.exit(main(get_args()))
+1 -2
View File
@@ -14,7 +14,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import print_function
import argparse
import glob
import os
@@ -71,7 +70,7 @@ def main(args):
util.print_test_result(tested, total, True, 'PASS', test_path)
except subprocess.CalledProcessError as err:
failed += 1
util.print_test_result(tested, total, False, 'FAIL (%d)' % err.returncode, test_path)
util.print_test_result(tested, total, False, f'FAIL ({err.returncode})', test_path)
print("================================================")
print(err.output)
print("================================================")
+88 -101
View File
@@ -40,10 +40,8 @@
# This code is governed by the BSD license found in the LICENSE file.
from __future__ import print_function
import logging
import optparse
import argparse
import os
from os import path
import platform
@@ -55,7 +53,6 @@ import xml.dom.minidom
from collections import Counter
import signal
import threading
import multiprocessing
#######################################################################
@@ -112,7 +109,7 @@ def my_read_dict(lines, indent=""):
def my_read_value(lines, value, indent):
if value == ">" or value == "|":
if value in (">", "|"):
(lines, value) = my_multiline(lines, value == "|")
value = value + "\n"
return (lines, value)
@@ -157,7 +154,7 @@ def my_remove_list_header(indent, line):
def my_read_one_line(value):
if M_YAML_LIST_PATTERN.match(value):
return my_flow_list(value)
elif re.match(r"^[-0-9]*$", value):
if re.match(r"^[-0-9]*$", value):
try:
value = int(value)
except ValueError:
@@ -196,7 +193,7 @@ def my_multiline(lines, preserve_newlines=False):
break
else:
if preserve_newlines:
if was_empty != None:
if was_empty is not None:
value += "\n"
else:
if was_empty:
@@ -248,7 +245,7 @@ _LICENSE_PATTERN = re.compile(
def yaml_attr_parser(test_record, attrs, name, onerror=print):
parsed = yaml_load(attrs)
if parsed is None:
onerror("Failed to parse yaml in name %s" % name)
onerror(f"Failed to parse yaml in name {name}")
return
for key in parsed:
@@ -287,7 +284,7 @@ def parse_test_record(src, name, onerror=print):
# YAML frontmatter is required for all tests.
if frontmatter is None:
onerror("Missing frontmatter: %s" % name)
onerror(f"Missing frontmatter: {name}")
# The license shuold be placed before the frontmatter and there shouldn't be
# any extra content between the license and the frontmatter.
@@ -295,13 +292,13 @@ def parse_test_record(src, name, onerror=print):
header_idx = src.index(header)
frontmatter_idx = src.index(frontmatter)
if header_idx > frontmatter_idx:
onerror("Unexpected license after frontmatter: %s" % name)
onerror(f"Unexpected license after frontmatter: {name}")
# Search for any extra test content, but ignore whitespace only or comment lines.
extra = src[header_idx + len(header): frontmatter_idx]
if extra and any(line.strip() and not line.lstrip().startswith("//") for line in extra.split("\n")):
onerror(
"Unexpected test content between license and frontmatter: %s" % name)
f"Unexpected test content between license and frontmatter: {name}")
# Remove the license and YAML parts from the actual test content.
test = src
@@ -319,7 +316,7 @@ def parse_test_record(src, name, onerror=print):
# Report if the license block is missing in non-generated tests.
if header is None and "generated" not in test_record and "hashbang" not in name:
onerror("No license found in: %s" % name)
onerror(f"No license found in: {name}")
return test_record
@@ -339,36 +336,37 @@ def report_error(error_string):
def build_options():
result = optparse.OptionParser()
result.add_option("--command", default=None,
help="The command-line to run")
result.add_option("--tests", default=path.abspath('.'),
help="Path to the tests")
result.add_option("--exclude-list", default=None,
help="Path to the excludelist.xml file")
result.add_option("--cat", default=False, action="store_true",
help="Print packaged test code that would be run")
result.add_option("--summary", default=False, action="store_true",
help="Print summary after running tests")
result.add_option("--full-summary", default=False, action="store_true",
help="Print summary and test output after running tests")
result.add_option("--strict_only", default=False, action="store_true",
help="Test only strict mode")
result.add_option("--non_strict_only", default=False, action="store_true",
help="Test only non-strict mode")
result.add_option("--unmarked_default", default="both",
help="default mode for tests of unspecified strictness")
result.add_option("-j", "--job-count", default=None, action="store", type=int,
help="Number of parallel test jobs to run. In case of '0' cpu count is used.")
result.add_option("--logname", help="Filename to save stdout to")
result.add_option("--loglevel", default="warning",
help="sets log level to debug, info, warning, error, or critical")
result.add_option("--print-handle", default="print",
help="Command to print from console")
result.add_option("--list-includes", default=False, action="store_true",
help="List includes required by tests")
result.add_option("--module-flag", default="-m",
help="List includes required by tests")
result = argparse.ArgumentParser()
result.add_argument("--command", default=None,
help="The command-line to run")
result.add_argument("--tests", default=path.abspath('.'),
help="Path to the tests")
result.add_argument("--exclude-list", default=None,
help="Path to the excludelist.xml file")
result.add_argument("--cat", default=False, action="store_true",
help="Print packaged test code that would be run")
result.add_argument("--summary", default=False, action="store_true",
help="Print summary after running tests")
result.add_argument("--full-summary", default=False, action="store_true",
help="Print summary and test output after running tests")
result.add_argument("--strict_only", default=False, action="store_true",
help="Test only strict mode")
result.add_argument("--non_strict_only", default=False, action="store_true",
help="Test only non-strict mode")
result.add_argument("--unmarked_default", default="both",
help="default mode for tests of unspecified strictness")
result.add_argument("-j", "--job-count", default=None, action="store", type=int,
help="Number of parallel test jobs to run. In case of '0' cpu count is used.")
result.add_argument("--logname", help="Filename to save stdout to")
result.add_argument("--loglevel", default="warning",
help="sets log level to debug, info, warning, error, or critical")
result.add_argument("--print-handle", default="print",
help="Command to print from console")
result.add_argument("--list-includes", default=False, action="store_true",
help="List includes required by tests")
result.add_argument("--module-flag", default="-m",
help="List includes required by tests")
result.add_argument("test_list", nargs='*', default=None)
return result
@@ -376,15 +374,15 @@ def validate_options(options):
if not options.command:
report_error("A --command must be specified.")
if not path.exists(options.tests):
report_error("Couldn't find test path '%s'" % options.tests)
report_error(f"Couldn't find test path '{options.tests}'")
def is_windows():
actual_platform = platform.system()
return (actual_platform == 'Windows') or (actual_platform == 'Microsoft')
return actual_platform in ('Windows', 'Microsoft')
class TempFile(object):
class TempFile:
def __init__(self, suffix="", prefix="tmp", text=False):
self.suffix = suffix
@@ -405,7 +403,7 @@ class TempFile(object):
os.write(self.file_desc, string.encode('utf8'))
def read(self):
with open(self.name, "r", newline='') as file_desc:
with open(self.name, "r", newline='', encoding='utf8') as file_desc:
return file_desc.read()
def close(self):
@@ -417,11 +415,11 @@ class TempFile(object):
try:
self.close()
os.unlink(self.name)
except OSError as exception:
logging.error("Error disposing temp file: %s", str(exception))
except OSError as os_error:
logging.error("Error disposing temp file: %s", os_error)
class TestResult(object):
class TestResult:
def __init__(self, exit_code, stdout, stderr, case):
self.exit_code = exit_code
@@ -433,37 +431,36 @@ class TestResult(object):
name = self.case.get_name()
mode = self.case.get_mode()
if self.exit_code != 0 and self.exit_code != 1:
sys.stderr.write(u"===%s failed in %s with negative:%s===\n"
% (name, mode, self.case.get_negative_type()))
if self.exit_code not in (0, 1):
sys.stderr.write(f"==={name} failed in {mode} with negative:{self.case.get_negative_type()}===\n")
self.write_output(sys.stderr)
if self.has_unexpected_outcome():
if self.case.is_negative():
print("=== %s passed in %s, but was expected to fail ===" % (name, mode))
print("--- expected error: %s ---\n" % self.case.get_negative_type())
print(f"=== {name} passed in {mode}, but was expected to fail ===")
print(f"--- expected error: {self.case.get_negative_type()} ---\n")
else:
if long_format:
print("=== %s failed in %s ===" % (name, mode))
print(f"=== {name} failed in {mode} ===")
else:
print("%s in %s: " % (name, mode))
print(f"{name} in {mode}: ")
self.write_output(sys.stdout)
if long_format:
print("===")
elif self.case.is_negative():
print("%s failed in %s as expected" % (name, mode))
print(f"{name} failed in {mode} as expected")
else:
print("%s passed in %s" % (name, mode))
print(f"{name} passed in {mode}")
def write_output(self, target):
out = self.stdout.strip()
if out:
target.write("--- output --- \n %s" % out)
target.write(f"--- output --- \n {out}")
error = self.stderr.strip()
if error:
target.write("--- errors --- \n %s" % error)
target.write(f"--- errors --- \n {error}")
target.write("\n--- exit code: %d ---\n" % self.exit_code)
target.write(f"\n--- exit code: {self.exit_code} ---\n")
def has_failed(self):
return self.exit_code != 0
@@ -486,14 +483,14 @@ class TestResult(object):
return self.stdout
class TestCase(object):
class TestCase:
def __init__(self, suite, name, full_path, strict_mode, command_template, module_flag):
self.suite = suite
self.name = name
self.full_path = full_path
self.strict_mode = strict_mode
with open(self.full_path, "r", newline='') as file_desc:
with open(self.full_path, "r", newline='', encoding='utf8') as file_desc:
self.contents = file_desc.read()
test_record = parse_test_record(self.contents, name)
self.test = test_record["test"]
@@ -602,25 +599,25 @@ class TestCase(object):
@staticmethod
def execute(command):
if is_windows():
args = '%s' % command
args = f'{command}'
else:
args = command.split(" ")
stdout = TempFile(prefix="test262-out-")
stderr = TempFile(prefix="test262-err-")
try:
logging.info("exec: %s", str(args))
process = subprocess.Popen(
with subprocess.Popen(
args,
shell=False,
stdout=stdout.file_desc,
stderr=stderr.file_desc
)
timer = threading.Timer(TEST262_CASE_TIMEOUT, process.kill)
timer.start()
code = process.wait()
timer.cancel()
out = stdout.read()
err = stderr.read()
) as process:
try:
code = process.wait(timeout=TEST262_CASE_TIMEOUT)
except subprocess.TimeoutExpired:
process.kill()
out = stdout.read()
err = stderr.read()
finally:
stdout.dispose()
stderr.dispose()
@@ -666,10 +663,10 @@ class TestCase(object):
if 'raw' in flags:
if 'noStrict' in flags:
raise TypeError("The `raw` flag implies the `noStrict` flag")
elif 'onlyStrict' in flags:
if 'onlyStrict' in flags:
raise TypeError(
"The `raw` flag is incompatible with the `onlyStrict` flag")
elif self.get_include_list():
if self.get_include_list():
raise TypeError(
"The `raw` flag is incompatible with the `includes` tag")
@@ -683,7 +680,7 @@ def test_case_run_process(case):
return case.run()
class ProgressIndicator(object):
class ProgressIndicator:
def __init__(self, count):
self.count = count
@@ -700,18 +697,11 @@ class ProgressIndicator(object):
self.succeeded += 1
def make_plural(num):
if num == 1:
return (num, "")
return (num, "s")
def percent_format(partial, total):
return "%i test%s (%.1f%%)" % (make_plural(partial) +
((100.0 * partial)/total,))
return f"{partial} test{'s' if partial > 1 else ''} ({(100.0 * partial)/total:.1f}%)"
class TestSuite(object):
class TestSuite:
def __init__(self, options):
self.test_root = path.join(options.tests, 'test')
@@ -760,7 +750,7 @@ class TestSuite(object):
if not name in self.include_cache:
static = path.join(self.lib_root, name)
if path.exists(static):
with open(static) as file_desc:
with open(static, encoding='utf8') as file_desc:
contents = file_desc.read()
contents = re.sub(r'\r\n', '\n', contents)
self.include_cache[name] = contents + "\n"
@@ -815,7 +805,7 @@ class TestSuite(object):
count = progress.count
succeeded = progress.succeeded
failed = progress.failed
write(" - Ran %i test%s" % make_plural(count))
write(f" - Ran {count} test{'s' if count > 1 else ''}")
if progress.failed == 0:
write(" - All tests succeeded")
else:
@@ -827,12 +817,12 @@ class TestSuite(object):
print("")
write("Failed Tests")
for result in positive:
write(" %s in %s" % (result.case.get_name(), result.case.get_mode()))
write(f" {result.case.get_name()} in {result.case.get_mode()}")
if negative:
print("")
write("Expected to fail but passed ---")
for result in negative:
write(" %s in %s" % (result.case.get_name(), result.case.get_mode()))
write(f" {result.case.get_name()} in {result.case.get_mode()}")
def print_failure_output(self, progress, logfile):
for result in progress.failed_tests:
@@ -849,7 +839,7 @@ class TestSuite(object):
report_error("No tests to run")
progress = ProgressIndicator(len(cases))
if logname:
self.logf = open(logname, "w")
self.logf = open(logname, "w", encoding='utf8') # pylint: disable=consider-using-with
if job_count == 1:
for case in cases:
@@ -861,15 +851,11 @@ class TestSuite(object):
if job_count == 0:
job_count = None # uses multiprocessing.cpu_count()
pool = multiprocessing.Pool(processes=job_count, initializer=pool_init)
try:
with multiprocessing.Pool(processes=job_count, initializer=pool_init) as pool:
for result in pool.imap(test_case_run_process, cases):
if logname:
self.write_log(result)
progress.has_run(result)
except KeyboardInterrupt:
pool.terminate()
pool.join()
if print_summary:
self.print_summary(progress, logname)
@@ -887,17 +873,17 @@ class TestSuite(object):
if result.has_unexpected_outcome():
if result.case.is_negative():
self.logf.write(
"=== %s passed in %s, but was expected to fail === \n" % (name, mode))
self.logf.write("--- expected error: %s ---\n" % result.case.GetNegativeType())
f"=== {name} passed in {mode}, but was expected to fail === \n")
self.logf.write(f"--- expected error: {result.case.GetNegativeType()} ---\n")
result.write_output(self.logf)
else:
self.logf.write("=== %s failed in %s === \n" % (name, mode))
self.logf.write(f"=== {name} failed in {mode} === \n")
result.write_output(self.logf)
self.logf.write("===\n")
elif result.case.is_negative():
self.logf.write("%s failed in %s as expected \n" % (name, mode))
self.logf.write(f"{name} failed in {mode} as expected \n")
else:
self.logf.write("%s passed in %s \n" % (name, mode))
self.logf.write(f"{name} passed in {mode} \n")
def print_source(self, tests):
cases = self.enumerate_tests(tests, "")
@@ -917,7 +903,8 @@ class TestSuite(object):
def main():
code = 0
parser = build_options()
(options, args) = parser.parse_args()
options = parser.parse_args()
args = options.test_list
validate_options(options)
test_suite = TestSuite(options)
@@ -951,5 +938,5 @@ if __name__ == '__main__':
try:
sys.exit(main())
except Test262Error as exception:
print("Error: %s" % exception.message)
print(f"Error: {exception.message}")
sys.exit(1)
+6 -9
View File
@@ -1,5 +1,3 @@
#!/usr/bin/env python
# Copyright JS Foundation and other contributors, http://js.foundation
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,7 +12,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import print_function
import signal
import subprocess
import sys
@@ -46,13 +43,13 @@ def set_sighdl_to_reset_timezone(timezone):
def print_test_summary(summary_string, total, passed, failed):
print("\n[summary] %s\n" % summary_string)
print("TOTAL: %d" % total)
print("%sPASS: %d%s" % (TERM_GREEN, passed, TERM_NORMAL))
print("%sFAIL: %d%s\n" % (TERM_RED, failed, TERM_NORMAL))
print(f"\n[summary] {summary_string}\n")
print(f"TOTAL: {total}")
print(f"{TERM_GREEN}PASS: {passed}{TERM_NORMAL}")
print(f"{TERM_RED}FAIL: {failed}{TERM_NORMAL}\n")
success_color = TERM_GREEN if passed == total else TERM_RED
print("%sSuccess: %d%%%s" % (success_color, passed*100/total, TERM_NORMAL))
print(f"{success_color}Success: {passed*100/total}{TERM_NORMAL}")
def print_test_result(tested, total, is_passed, passed_string, test_path, is_snapshot_generation=None):
@@ -64,7 +61,7 @@ def print_test_result(tested, total, is_passed, passed_string, test_path, is_sna
snapshot_string = ' (execute snapshot)'
color = TERM_GREEN if is_passed else TERM_RED
print("[%4d/%4d] %s%s: %s%s%s" % (tested, total, color, passed_string, test_path, snapshot_string, TERM_NORMAL))
print(f"[{tested:>4}/{total:>4}] {color}{passed_string}: {test_path}{snapshot_string}{TERM_NORMAL}")
def get_platform_cmd_prefix():